]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1494: crash when recovering from corrupted swap file v9.0.1494
authorBram Moolenaar <Bram@vim.org>
Thu, 27 Apr 2023 20:13:12 +0000 (21:13 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 27 Apr 2023 20:13:12 +0000 (21:13 +0100)
Problem:    Crash when recovering from corrupted swap file.
Solution:   Bail out when the line index looks wrong. (closes #12276)

src/memline.c
src/testdir/test_recover.vim
src/version.c

index 527552cff2bb96e9f1313107f36d47527c9d08b7..af354a5bffbca854274bfcc674e782a0ab25d58f 100644 (file)
@@ -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)
index 13437cd8ed6d5a404d53037e1a901f83e24de1d4..8af139736581152e8b70e7177c2bcf60bb481163 100644 (file)
@@ -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
index bc2c94521453f8732941ec7e39554007aa124558..929308c07a5309356fe02b49956527d44d23d9d5 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1494,
 /**/
     1493,
 /**/