summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2023-04-27 21:13:12 +0100
committerBram Moolenaar <Bram@vim.org>2023-04-27 21:13:12 +0100
commitbf1b7132021bac0fccefebb4a1c24a5f372bae4f (patch)
tree01932a26a2c33f50237f29edda2e18d5e1316203
parent4e1ca0d9a6c6d66987da67155e97f83f286ffbcc (diff)
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.c41
-rw-r--r--src/testdir/test_recover.vim15
-rw-r--r--src/version.c2
3 files changed, 46 insertions, 12 deletions
diff --git a/src/memline.c b/src/memline.c
index 527552cff2..af354a5bff 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 13437cd8ed..8af1397365 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 bc2c945214..929308c07a 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,