Patch 9.0.1477
Problem:    Crash when recovering from corrupted swap file.
Solution:   Check for a valid page count. (closes #12275)
Files:      src/memfile.c, src/memline.c, src/errors.h,
            src/testdir/test_recover.vim


*** ../vim-9.0.1476/src/memfile.c       2023-01-14 12:32:24.219984103 +0000
--- src/memfile.c       2023-04-22 20:39:53.820244408 +0100
***************
*** 431,437 ****
         * If not, allocate a new block.
         */
        hp = mf_release(mfp, page_count);
!       if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
            return NULL;
  
        hp->bh_bnum = nr;
--- 431,439 ----
         * If not, allocate a new block.
         */
        hp = mf_release(mfp, page_count);
!       if (hp == NULL && page_count > 0)
!           hp = mf_alloc_bhdr(mfp, page_count);
!       if (hp == NULL)
            return NULL;
  
        hp->bh_bnum = nr;
***************
*** 812,820 ****
       */
      if (hp->bh_page_count != page_count)
      {
!       vim_free(hp->bh_data);
!       if ((hp->bh_data = alloc((size_t)mfp->mf_page_size * page_count))
!                                                                      == NULL)
        {
            vim_free(hp);
            return NULL;
--- 814,823 ----
       */
      if (hp->bh_page_count != page_count)
      {
!       VIM_CLEAR(hp->bh_data);
!       if (page_count > 0)
!           hp->bh_data = alloc((size_t)mfp->mf_page_size * page_count);
!       if (hp->bh_data == NULL)
        {
            vim_free(hp);
            return NULL;
***************
*** 872,878 ****
  }
  
  /*
!  * Allocate a block header and a block of memory for it
   */
      static bhdr_T *
  mf_alloc_bhdr(memfile_T *mfp, int page_count)
--- 875,881 ----
  }
  
  /*
!  * Allocate a block header and a block of memory for it.
   */
      static bhdr_T *
  mf_alloc_bhdr(memfile_T *mfp, int page_count)
***************
*** 882,889 ****
      if ((hp = ALLOC_ONE(bhdr_T)) == NULL)
        return NULL;
  
!     if ((hp->bh_data = alloc((size_t)mfp->mf_page_size * page_count))
!           == NULL)
      {
        vim_free(hp);       // not enough memory
        return NULL;
--- 885,891 ----
      if ((hp = ALLOC_ONE(bhdr_T)) == NULL)
        return NULL;
  
!     if ((hp->bh_data = alloc((size_t)mfp->mf_page_size * page_count)) == NULL)
      {
        vim_free(hp);       // not enough memory
        return NULL;
***************
*** 893,899 ****
  }
  
  /*
!  * Free a block header and the block of memory for it
   */
      static void
  mf_free_bhdr(bhdr_T *hp)
--- 895,901 ----
  }
  
  /*
!  * Free a block header and the block of memory for it.
   */
      static void
  mf_free_bhdr(bhdr_T *hp)
***************
*** 903,909 ****
  }
  
  /*
!  * insert entry *hp in the free list
   */
      static void
  mf_ins_free(memfile_T *mfp, bhdr_T *hp)
--- 905,911 ----
  }
  
  /*
!  * Insert entry *hp in the free list.
   */
      static void
  mf_ins_free(memfile_T *mfp, bhdr_T *hp)
*** ../vim-9.0.1476/src/memline.c       2023-02-01 13:11:11.714991151 +0000
--- src/memline.c       2023-04-22 21:01:59.296312442 +0100
***************
*** 98,103 ****
--- 98,106 ----
                                // followed by empty space until end of page
  };
  
+ // Value for pb_count_max.
+ #define PB_COUNT_MAX(mfp) (short_u)(((mfp)->mf_page_size - offsetof(PTR_BL, 
pb_pointer)) / sizeof(PTR_EN))
+ 
  /*
   * A data block is a leaf in the tree.
   *
***************
*** 1525,1530 ****
--- 1528,1547 ----
            pp = (PTR_BL *)(hp->bh_data);
            if (pp->pb_id == PTR_ID)            // it is a pointer block
            {
+               int ptr_block_error = FALSE;
+               if (pp->pb_count_max != PB_COUNT_MAX(mfp))
+               {
+                   ptr_block_error = TRUE;
+                   pp->pb_count_max = PB_COUNT_MAX(mfp);
+               }
+               if (pp->pb_count > pp->pb_count_max)
+               {
+                   ptr_block_error = TRUE;
+                   pp->pb_count = pp->pb_count_max;
+               }
+               if (ptr_block_error)
+                   emsg(_(e_warning_pointer_block_corrupted));
+ 
                // check line count when using pointer block first time
                if (idx == 0 && line_count != 0)
                {
***************
*** 4162,4170 ****
      pp = (PTR_BL *)(hp->bh_data);
      pp->pb_id = PTR_ID;
      pp->pb_count = 0;
!     pp->pb_count_max =
!       (short_u)((mfp->mf_page_size - offsetof(PTR_BL, pb_pointer))
!                                                            / sizeof(PTR_EN));
  
      return hp;
  }
--- 4179,4185 ----
      pp = (PTR_BL *)(hp->bh_data);
      pp->pb_id = PTR_ID;
      pp->pb_count = 0;
!     pp->pb_count_max = PB_COUNT_MAX(mfp);
  
      return hp;
  }
*** ../vim-9.0.1476/src/errors.h        2023-04-13 19:15:50.027391986 +0100
--- src/errors.h        2023-04-22 20:59:04.348375914 +0100
***************
*** 3459,3461 ****
--- 3459,3463 ----
  EXTERN char e_incomplete_type[]
        INIT(= N_("E1363: Incomplete type"));
  #endif
+ EXTERN char e_warning_pointer_block_corrupted[]
+       INIT(= N_("E1364: Warning: Pointer block corrupted"));
*** ../vim-9.0.1476/src/testdir/test_recover.vim        2022-11-17 
15:23:48.458617558 +0000
--- src/testdir/test_recover.vim        2023-04-22 21:10:52.468573068 +0100
***************
*** 249,254 ****
--- 249,262 ----
    call assert_equal(['???EMPTY BLOCK'], getline(1, '$'))
    bw!
  
+   " set the number of pointers in a pointer block to a large value
+   let b = copy(save_b)
+   let b[4098:4099] = 0zFFFF
+   call writefile(b, sn)
+   call assert_fails('recover Xfile1', 'E1364:')
+   call assert_equal('Xfile1', @%)
+   bw!
+ 
    " set the block number in a pointer entry to a negative number
    let b = copy(save_b)
    if system_64bit
*** ../vim-9.0.1476/src/version.c       2023-04-22 15:35:08.861815544 +0100
--- src/version.c       2023-04-22 20:30:31.356016527 +0100
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1477,
  /**/

-- 
INSPECTOR END OF FILM: Move along.  There's nothing to see!  Keep moving!
   [Suddenly he notices the cameras.]
INSPECTOR END OF FILM: (to Camera) All right, put that away sonny.
   [He walks over to it and puts his hand over the lens.]
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230422201457.35FED1C074F%40moolenaar.net.

Raspunde prin e-mail lui