mirror of
https://github.com/neovim/neovim.git
synced 2025-09-28 14:08:32 +00:00
vim-patch:9.1.1567: crash when using inline diff mode (#35005)
Problem: Crash when using inline diff mode
(Ilya Grigoriev)
Solution: Set tp_diffbuf to NULL when skipping a diff block
(Yee Cheng Chin).
Fix an array out of bounds crash when using diffopt+=inline:char when 4
or more buffers are being diff'ed. This happens when one of the blocks
is empty. The inline highlight logic skips using that buffer's block,
but when another buffer is used later and calls diff_read() to merge the
diff blocks together, it could erroneously consider the empty block's
diff info which has not been initialized, leaving to diff numbers that
are invalid. Later on the diff num is used without bounds checking which
leads to the crash.
Fix this by making sure to unset tp_diffbuf to NULL when we skip a
block, so diff_read() will not consider this buffer to be used within
inline diff. Also, add more bounds checking just to be safe.
closes: vim/vim#17805
c8b99e2d13
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
This commit is contained in:
@@ -3092,6 +3092,11 @@ static void diff_find_change_inline_diff(diff_T *dp)
|
||||
diff_T *orig_diff = curtab->tp_first_diff;
|
||||
curtab->tp_first_diff = NULL;
|
||||
|
||||
// diff_read() also uses curtab->tp_diffbuf to determine what's an active
|
||||
// buffer
|
||||
buf_T *(orig_diffbuf[DB_COUNT]);
|
||||
memcpy(orig_diffbuf, curtab->tp_diffbuf, sizeof(orig_diffbuf));
|
||||
|
||||
garray_T linemap[DB_COUNT];
|
||||
garray_T file1_str;
|
||||
garray_T file2_str;
|
||||
@@ -3118,8 +3123,12 @@ static void diff_find_change_inline_diff(diff_T *dp)
|
||||
continue; // skip buffer that isn't loaded
|
||||
}
|
||||
if (dp->df_count[i] == 0) {
|
||||
continue; // skip buffer that don't have any texts in this block
|
||||
// skip buffers that don't have any texts in this block so we don't
|
||||
// end up marking the entire block as modified in multi-buffer diff
|
||||
curtab->tp_diffbuf[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file1_idx == -1) {
|
||||
file1_idx = i;
|
||||
}
|
||||
@@ -3297,7 +3306,7 @@ static void diff_find_change_inline_diff(diff_T *dp)
|
||||
for (; new_diff != NULL; new_diff = new_diff->df_next) {
|
||||
diffline_change_T change = { 0 };
|
||||
for (int i = 0; i < DB_COUNT; i++) {
|
||||
if (new_diff->df_lnum[i] == 0) {
|
||||
if (new_diff->df_lnum[i] <= 0) { // should never be < 0. Checking just for safety
|
||||
continue;
|
||||
}
|
||||
linenr_T diff_lnum = new_diff->df_lnum[i] - 1; // use zero-index
|
||||
@@ -3334,6 +3343,7 @@ done:
|
||||
|
||||
diff_clear(curtab);
|
||||
curtab->tp_first_diff = orig_diff;
|
||||
memcpy(curtab->tp_diffbuf, orig_diffbuf, sizeof(orig_diffbuf));
|
||||
|
||||
ga_clear(&file1_str);
|
||||
ga_clear(&file2_str);
|
||||
|
Reference in New Issue
Block a user