diff --git a/contrib/libdiff/include/diff_main.h b/contrib/libdiff/include/diff_main.h --- a/contrib/libdiff/include/diff_main.h +++ b/contrib/libdiff/include/diff_main.h @@ -118,6 +118,7 @@ /* Flags set by file atomizer. */ #define DIFF_ATOMIZER_FOUND_BINARY_DATA 0x00000001 +#define DIFF_ATOMIZER_FILE_TRUNCATED 0x00000002 /* Flags set by caller of diff_main(). */ #define DIFF_FLAG_IGNORE_WHITESPACE 0x00000001 diff --git a/contrib/libdiff/lib/diff_atomize_text.c b/contrib/libdiff/lib/diff_atomize_text.c --- a/contrib/libdiff/lib/diff_atomize_text.c +++ b/contrib/libdiff/lib/diff_atomize_text.c @@ -16,6 +16,8 @@ */ #include +#include +#include #include #include #include @@ -122,10 +124,18 @@ return DIFF_RC_OK; } +static sigjmp_buf diff_data_signal_env; +static void +diff_data_signal_handler(int sig) +{ + siglongjmp(diff_data_signal_env, sig); +} + static int diff_data_atomize_text_lines_mmap(struct diff_data *d) { - const uint8_t *pos = d->data; + struct sigaction act, oact; + const uint8_t *volatile pos = d->data; const uint8_t *end = pos + d->len; bool ignore_whitespace = (d->diff_flags & DIFF_FLAG_IGNORE_WHITESPACE); bool embedded_nul = false; @@ -136,8 +146,22 @@ ARRAYLIST_INIT(d->atoms, 1 << pow2); + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = diff_data_signal_handler; + sigaction(SIGBUS, &act, &oact); + if (sigsetjmp(diff_data_signal_env, 0) > 0) { + /* + * The file was truncated while we were reading it. Set + * the end pointer to the beginning of the line we were + * trying to read, adjust the file length, and set a flag. + */ + end = pos; + d->len = end - d->data; + d->atomizer_flags |= DIFF_ATOMIZER_FILE_TRUNCATED; + } while (pos < end) { - const uint8_t *line_end = pos; + const uint8_t *line_start = pos, *line_end = pos; unsigned int hash = 0; while (line_end < end && *line_end != '\r' && *line_end != '\n') { @@ -164,15 +188,16 @@ *atom = (struct diff_atom){ .root = d, - .pos = (off_t)(pos - d->data), - .at = pos, - .len = line_end - pos, + .pos = (off_t)(line_start - d->data), + .at = line_start, + .len = line_end - line_start, .hash = hash, }; /* Starting point for next line: */ pos = line_end; } + sigaction(SIGBUS, &oact, NULL); /* File are considered binary if they contain embedded '\0' bytes. */ if (embedded_nul)