diff options
author | Bram Moolenaar <Bram@vim.org> | 2023-04-27 21:13:12 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2023-04-27 21:13:12 +0100 |
commit | bf1b7132021bac0fccefebb4a1c24a5f372bae4f (patch) | |
tree | 01932a26a2c33f50237f29edda2e18d5e1316203 | |
parent | 4e1ca0d9a6c6d66987da67155e97f83f286ffbcc (diff) | |
download | vim-git-bf1b7132021bac0fccefebb4a1c24a5f372bae4f.tar.gz |
patch 9.0.1494: crash when recovering from corrupted swap filev9.0.1494
Problem: Crash when recovering from corrupted swap file.
Solution: Bail out when the line index looks wrong. (closes #12276)
-rw-r--r-- | src/memline.c | 41 | ||||
-rw-r--r-- | src/testdir/test_recover.vim | 15 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 46 insertions, 12 deletions
diff --git a/src/memline.c b/src/memline.c index 527552cff..af354a5bf 100644 --- a/src/memline.c +++ b/src/memline.c @@ -1637,14 +1637,13 @@ ml_recover(int checkext) else { /* - * it is a data block - * Append all the lines in this block + * It is a data block. + * Append all the lines in this block. */ has_error = FALSE; - /* - * check length of block - * if wrong, use length in pointer block - */ + + // Check the length of the block. + // If wrong, use the length given in the pointer block. if (page_count * mfp->mf_page_size != dp->db_txt_end) { ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"), @@ -1654,13 +1653,12 @@ ml_recover(int checkext) dp->db_txt_end = page_count * mfp->mf_page_size; } - // make sure there is a NUL at the end of the block + // Make sure there is a NUL at the end of the block so we + // don't go over the end when copying text. *((char_u *)dp + dp->db_txt_end - 1) = NUL; - /* - * check number of lines in block - * if wrong, use count in data block - */ + // Check the number of lines in the block. + // If wrong, use the count in the data block. if (line_count != dp->db_line_count) { ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"), @@ -1669,17 +1667,36 @@ ml_recover(int checkext) has_error = TRUE; } + int did_questions = FALSE; for (i = 0; i < dp->db_line_count; ++i) { + if ((char_u *)&(dp->db_index[i]) + >= (char_u *)dp + dp->db_txt_start) + { + // line count must be wrong + ++error; + ml_append(lnum++, + (char_u *)_("??? lines may be missing"), + (colnr_T)0, TRUE); + break; + } + txt_start = (dp->db_index[i] & DB_INDEX_MASK); if (txt_start <= (int)HEADER_SIZE || txt_start >= (int)dp->db_txt_end) { - p = (char_u *)"???"; ++error; + // avoid lots of lines with "???" + if (did_questions) + continue; + did_questions = TRUE; + p = (char_u *)"???"; } else + { + did_questions = FALSE; p = (char_u *)dp + txt_start; + } ml_append(lnum++, p, (colnr_T)0, TRUE); } if (has_error) diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim index 13437cd8e..8af139736 100644 --- a/src/testdir/test_recover.vim +++ b/src/testdir/test_recover.vim @@ -293,6 +293,21 @@ func Test_recover_corrupted_swap_file() \ '???END'], getline(1, '$')) bw! + " set the number of lines in the data block to a large value + let b = copy(save_b) + if system_64bit + let b[8208:8215] = 0z00FFFFFF.FFFFFF00 + else + let b[8208:8211] = 0z00FFFF00 + endif + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['??? from here until ???END lines may have been inserted/deleted', + \ '', '???', '??? lines may be missing', + \ '???END'], getline(1, '$')) + bw! + " use an invalid text start for the lines in a data block let b = copy(save_b) if system_64bit diff --git a/src/version.c b/src/version.c index bc2c94521..929308c07 100644 --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1494, +/**/ 1493, /**/ 1492, |