diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 960b6bd264..9810e30f21 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -1565,36 +1565,48 @@ void u_read_undo(char *name, const uint8_t *hash, const char *orig_name FUNC_ATT goto error; } } - for (int j = 0; j < num_head; j++) { - if (uhp_table[j] != NULL - && uhp_table[j]->uh_seq == uhp->uh_next.seq) { - uhp->uh_next.ptr = uhp_table[j]; - SET_FLAG(j); - break; + { + const int seq = uhp->uh_next.seq; + uhp->uh_next.ptr = NULL; + for (int j = 0; j < num_head; j++) { + if (uhp_table[j] != NULL && i != j && uhp_table[j]->uh_seq == seq) { + uhp->uh_next.ptr = uhp_table[j]; + SET_FLAG(j); + break; + } } } - for (int j = 0; j < num_head; j++) { - if (uhp_table[j] != NULL - && uhp_table[j]->uh_seq == uhp->uh_prev.seq) { - uhp->uh_prev.ptr = uhp_table[j]; - SET_FLAG(j); - break; + { + const int seq = uhp->uh_prev.seq; + uhp->uh_prev.ptr = NULL; + for (int j = 0; j < num_head; j++) { + if (uhp_table[j] != NULL && i != j && uhp_table[j]->uh_seq == seq) { + uhp->uh_prev.ptr = uhp_table[j]; + SET_FLAG(j); + break; + } } } - for (int j = 0; j < num_head; j++) { - if (uhp_table[j] != NULL - && uhp_table[j]->uh_seq == uhp->uh_alt_next.seq) { - uhp->uh_alt_next.ptr = uhp_table[j]; - SET_FLAG(j); - break; + { + const int seq = uhp->uh_alt_next.seq; + uhp->uh_alt_next.ptr = NULL; + for (int j = 0; j < num_head; j++) { + if (uhp_table[j] != NULL && i != j && uhp_table[j]->uh_seq == seq) { + uhp->uh_alt_next.ptr = uhp_table[j]; + SET_FLAG(j); + break; + } } } - for (int j = 0; j < num_head; j++) { - if (uhp_table[j] != NULL - && uhp_table[j]->uh_seq == uhp->uh_alt_prev.seq) { - uhp->uh_alt_prev.ptr = uhp_table[j]; - SET_FLAG(j); - break; + { + const int seq = uhp->uh_alt_prev.seq; + uhp->uh_alt_prev.ptr = NULL; + for (int j = 0; j < num_head; j++) { + if (uhp_table[j] != NULL && i != j && uhp_table[j]->uh_seq == seq) { + uhp->uh_alt_prev.ptr = uhp_table[j]; + SET_FLAG(j); + break; + } } } if (old_header_seq > 0 && old_idx < 0 && uhp->uh_seq == old_header_seq) { diff --git a/test/old/testdir/test_undo.vim b/test/old/testdir/test_undo.vim index fe3d5f8209..2527c43f40 100644 --- a/test/old/testdir/test_undo.vim +++ b/test/old/testdir/test_undo.vim @@ -924,4 +924,43 @@ func Test_restore_cursor_position_after_undo() endfunc +" Corrupted undo file via cyclic cross-references caused +" double free +func Test_corrupted_undofile() + CheckFeature persistent_undo + let _uf = &undofile + set undofile + new + call setline(1, 'hello') + let b=eval('0z56696D9F556E446FE50002F3AEFE62965A91903610' .. + \ 'F0E23CC8A69D5B87CEA6D28E75489B0D2CA02ED7993C' .. + \ '00000001000000000000000000000000000000010000' .. + \ '00010000000100000001000000010000000100000000' .. + \ '3B9ACA00005FD0000000010000000000000000000000' .. + \ '00000000010000000100000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '00000000000000000000000000000000000000000000' .. + \ '000000000000000000000000000000000000003B9ACA' .. + \ '00003581E7AA') + " Nvim: convert undo file format + let b = b->slice(0, -2) + 0z3581 + b->slice(-2) | let b[10] = 0x03 + call writefile(b, 'Xundo', 'bD') + rundo Xundo + bw! + let &undofile = _uf +endfunc + " vim: shiftwidth=2 sts=2 expandtab