aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editor.c2
-rw-r--r--editor.h4
-rw-r--r--text.c8
-rw-r--r--text.h3
-rw-r--r--vis.c35
5 files changed, 52 insertions, 0 deletions
diff --git a/editor.c b/editor.c
index ad9bd4e..8628458 100644
--- a/editor.c
+++ b/editor.c
@@ -358,6 +358,8 @@ void editor_window_close(Win *win) {
ed->windows = win->next;
if (ed->win == win)
ed->win = win->next ? win->next : win->prev;
+ if (ed->prompt_window == win)
+ ed->prompt_window = NULL;
window_free(win);
if (ed->win)
ed->ui->window_focus(ed->win->ui);
diff --git a/editor.h b/editor.h
index 76a3136..3e8e644 100644
--- a/editor.h
+++ b/editor.h
@@ -5,6 +5,7 @@
#include <signal.h>
#include <stddef.h>
#include <stdbool.h>
+#include <setjmp.h>
typedef struct Editor Editor;
typedef struct File File;
@@ -190,6 +191,7 @@ enum Mark {
struct File {
Text *text;
const char *name;
+ volatile sig_atomic_t truncated;
bool is_stdin;
struct stat stat;
int refcount;
@@ -244,6 +246,8 @@ struct Editor {
Mode *mode_before_prompt; /* user mode which was active before entering prompt */
volatile bool running; /* exit main loop once this becomes false */
volatile sig_atomic_t cancel_filter; /* abort external command */
+ volatile sig_atomic_t sigbus;
+ sigjmp_buf sigbus_jmpbuf;
};
Editor *editor_new(Ui*);
diff --git a/text.c b/text.c
index be9a8f5..5f516bc 100644
--- a/text.c
+++ b/text.c
@@ -1185,6 +1185,14 @@ bool text_modified(Text *txt) {
return txt->saved_action != txt->history;
}
+bool text_sigbus(Text *txt, const char *addr) {
+ for (Buffer *buf = txt->buffers; buf; buf = buf->next) {
+ if (buf->type == MMAP && buf->data <= addr && addr < buf->data + buf->size)
+ return true;
+ }
+ return false;
+}
+
enum TextNewLine text_newline_type(Text *txt){
if (!txt->newlines) {
txt->newlines = TEXT_NEWLINE_NL; /* default to UNIX style \n new lines */
diff --git a/text.h b/text.h
index c322a10..89a5d9b 100644
--- a/text.h
+++ b/text.h
@@ -108,6 +108,9 @@ size_t text_history_get(Text*, size_t index);
size_t text_size(Text*);
/* query whether the text contains any unsaved modifications */
bool text_modified(Text*);
+/* query whether `addr` is part of a memory mapped region associated with
+ * this text instance */
+bool text_sigbus(Text*, const char *addr);
/* which type of new lines does the text use? */
enum TextNewLine {
diff --git a/vis.c b/vis.c
index 8e51bce..ffe45ce 100644
--- a/vis.c
+++ b/vis.c
@@ -2312,8 +2312,23 @@ static Key getkey(void) {
return key;
}
+static void sigbus_handler(int sig, siginfo_t *siginfo, void *context) {
+ for (File *file = vis->files; file; file = file->next) {
+ if (text_sigbus(file->text, siginfo->si_addr))
+ file->truncated = true;
+ }
+ vis->sigbus = true;
+ siglongjmp(vis->sigbus_jmpbuf, 1);
+}
+
static void mainloop() {
struct timespec idle = { .tv_nsec = 0 }, *timeout = NULL;
+ struct sigaction sa_sigbus;
+ memset(&sa_sigbus, 0, sizeof sa_sigbus);
+ sa_sigbus.sa_flags = SA_SIGINFO;
+ sa_sigbus.sa_sigaction = sigbus_handler;
+ if (sigaction(SIGBUS, &sa_sigbus, NULL))
+ die("sigaction: %s", strerror(errno));
sigset_t emptyset, blockset;
sigemptyset(&emptyset);
sigemptyset(&blockset);
@@ -2323,11 +2338,31 @@ static void mainloop() {
editor_draw(vis);
vis->running = true;
+ sigsetjmp(vis->sigbus_jmpbuf, 1);
+
while (vis->running) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
+ if (vis->sigbus) {
+ char *name = NULL;
+ for (Win *next, *win = vis->windows; win; win = next) {
+ next = win->next;
+ if (win->file->truncated) {
+ free(name);
+ name = strdup(win->file->name);
+ editor_window_close(win);
+ }
+ }
+ if (!vis->windows)
+ die("WARNING: file `%s' truncated!\n", name ? name : "-");
+ else
+ editor_info_show(vis, "WARNING: file `%s' truncated!\n", name ? name : "-");
+ vis->sigbus = false;
+ free(name);
+ }
+
editor_update(vis);
idle.tv_sec = vis->mode->idle_timeout;
int r = pselect(1, &fds, NULL, NULL, timeout, &emptyset);