aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-04-28 06:27:51 +0800
committerGitHub <noreply@github.com>2023-04-28 06:27:51 +0800
commit95839a23581ad678e6dc34bc2935d78f516639e7 (patch)
tree5f36f205af7fce2c13122993fe2323e6557f720f
parent50107c37782fdeae7ad498c29d37a48cac87d657 (diff)
downloadrneovim-95839a23581ad678e6dc34bc2935d78f516639e7.tar.gz
rneovim-95839a23581ad678e6dc34bc2935d78f516639e7.tar.bz2
rneovim-95839a23581ad678e6dc34bc2935d78f516639e7.zip
vim-patch:9.0.1494: crash when recovering from corrupted swap file (#23358)
Problem: Crash when recovering from corrupted swap file. Solution: Bail out when the line index looks wrong. (closes vim/vim#12276) https://github.com/vim/vim/commit/bf1b7132021bac0fccefebb4a1c24a5f372bae4f Co-authored-by: Bram Moolenaar <Bram@vim.org>
-rw-r--r--src/nvim/memline.c32
-rw-r--r--test/old/testdir/test_recover.vim15
2 files changed, 39 insertions, 8 deletions
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 0400949eae..5dffd5e933 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -1070,11 +1070,12 @@ void ml_recover(bool checkext)
ml_append(lnum++, _("???BLOCK MISSING"),
(colnr_T)0, true);
} 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.
bool 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++,
_("??? from here until ???END lines" " may be messed up"),
@@ -1084,11 +1085,12 @@ void ml_recover(bool 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 *)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++,
_("??? from here until ???END lines"
@@ -1098,13 +1100,27 @@ void ml_recover(bool checkext)
has_error = true;
}
+ bool did_questions = false;
for (int i = 0; i < dp->db_line_count; i++) {
+ if ((char *)&(dp->db_index[i]) >= (char *)dp + dp->db_txt_start) {
+ // line count must be wrong
+ error++;
+ ml_append(lnum++, _("??? lines may be missing"), (colnr_T)0, true);
+ break;
+ }
+
int txt_start = (dp->db_index[i] & DB_INDEX_MASK);
if (txt_start <= (int)HEADER_SIZE
|| txt_start >= (int)dp->db_txt_end) {
- p = "???";
error++;
+ // avoid lots of lines with "???"
+ if (did_questions) {
+ continue;
+ }
+ did_questions = true;
+ p = "???";
} else {
+ did_questions = false;
p = (char *)dp + txt_start;
}
ml_append(lnum++, p, (colnr_T)0, true);
diff --git a/test/old/testdir/test_recover.vim b/test/old/testdir/test_recover.vim
index 81e2dde1e2..e5ea144d31 100644
--- a/test/old/testdir/test_recover.vim
+++ b/test/old/testdir/test_recover.vim
@@ -303,6 +303,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