diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-04-23 08:24:10 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-23 08:24:10 +0800 |
commit | 77ff25b1d9ab5869d852779cae8fc6a1245f3ea7 (patch) | |
tree | 0eaf8af285049ca4972d127724bb26a465876c61 | |
parent | 431b152726013ec6a5cece0285e7c103673bc511 (diff) | |
download | rneovim-77ff25b1d9ab5869d852779cae8fc6a1245f3ea7.tar.gz rneovim-77ff25b1d9ab5869d852779cae8fc6a1245f3ea7.tar.bz2 rneovim-77ff25b1d9ab5869d852779cae8fc6a1245f3ea7.zip |
vim-patch:9.0.1477: crash when recovering from corrupted swap file (#23273)
Problem: Crash when recovering from corrupted swap file.
Solution: Check for a valid page count. (closes vim/vim#12275)
https://github.com/vim/vim/commit/b67ba03d3ef2e6c5f207d508e85fc6906f938028
Co-authored-by: Bram Moolenaar <Bram@vim.org>
-rw-r--r-- | src/nvim/memfile.c | 7 | ||||
-rw-r--r-- | src/nvim/memline.c | 23 | ||||
-rw-r--r-- | test/old/testdir/test_recover.vim | 8 |
3 files changed, 35 insertions, 3 deletions
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 51fa17384c..3eac44b40b 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -300,7 +300,12 @@ bhdr_T *mf_get(memfile_T *mfp, blocknr_T nr, unsigned page_count) // could check here if the block is in the free list - hp = mf_alloc_bhdr(mfp, page_count); + if (page_count > 0) { + hp = mf_alloc_bhdr(mfp, page_count); + } + if (hp == NULL) { + return NULL; + } hp->bh_bnum = nr; hp->bh_flags = 0; diff --git a/src/nvim/memline.c b/src/nvim/memline.c index cb58cbc86f..b91a0a9169 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -121,6 +121,10 @@ struct pointer_block { // followed by empty space until end of page }; +// Value for pb_count_max. +#define PB_COUNT_MAX(mfp) \ + (uint16_t)((mfp->mf_page_size - offsetof(PTR_BL, pb_pointer)) / sizeof(PTR_EN)) + // A data block is a leaf in the tree. // // The text of the lines is at the end of the block. The text of the first line @@ -244,6 +248,9 @@ typedef enum { # include "memline.c.generated.h" #endif +static char e_warning_pointer_block_corrupted[] + = N_("E1364: Warning: Pointer block corrupted"); + #if __has_feature(address_sanitizer) # define ML_GET_ALLOC_LINES #endif @@ -986,6 +993,19 @@ void ml_recover(bool checkext) } else { // there is a block pp = hp->bh_data; if (pp->pb_id == PTR_ID) { // it is a pointer block + bool 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) { for (int i = 0; i < (int)pp->pb_count; i++) { @@ -2752,8 +2772,7 @@ static bhdr_T *ml_new_ptr(memfile_T *mfp) PTR_BL *pp = hp->bh_data; pp->pb_id = PTR_ID; pp->pb_count = 0; - pp->pb_count_max - = (uint16_t)((mfp->mf_page_size - offsetof(PTR_BL, pb_pointer)) / sizeof(PTR_EN)); + pp->pb_count_max = PB_COUNT_MAX(mfp); return hp; } diff --git a/test/old/testdir/test_recover.vim b/test/old/testdir/test_recover.vim index 92e22687af..81e2dde1e2 100644 --- a/test/old/testdir/test_recover.vim +++ b/test/old/testdir/test_recover.vim @@ -259,6 +259,14 @@ func Test_recover_corrupted_swap_file() 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 |