aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-04-23 08:24:10 +0800
committerGitHub <noreply@github.com>2023-04-23 08:24:10 +0800
commit77ff25b1d9ab5869d852779cae8fc6a1245f3ea7 (patch)
tree0eaf8af285049ca4972d127724bb26a465876c61
parent431b152726013ec6a5cece0285e7c103673bc511 (diff)
downloadrneovim-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.c7
-rw-r--r--src/nvim/memline.c23
-rw-r--r--test/old/testdir/test_recover.vim8
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