Merge pull request #23359 from neovim/backport-23358-to-release-0.9

[Backport release-0.9] vim-patch:9.0.1494: crash when recovering from corrupted swap file
This commit is contained in:
zeertzjq
2023-04-28 09:23:22 +08:00
committed by GitHub
2 changed files with 39 additions and 8 deletions

View File

@@ -1070,11 +1070,12 @@ void ml_recover(bool checkext)
ml_append(lnum++, _("???BLOCK MISSING"), ml_append(lnum++, _("???BLOCK MISSING"),
(colnr_T)0, true); (colnr_T)0, true);
} else { } else {
// it is a data block // It is a data block.
// Append all the lines in this block // Append all the lines in this block.
bool has_error = false; 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) { if (page_count * mfp->mf_page_size != dp->db_txt_end) {
ml_append(lnum++, ml_append(lnum++,
_("??? from here until ???END lines" " may be messed up"), _("??? 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; 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; *((char *)dp + dp->db_txt_end - 1) = NUL;
// check number of lines in block // Check the number of lines in the block.
// if wrong, use count in data block // If wrong, use the count in the data block.
if (line_count != dp->db_line_count) { if (line_count != dp->db_line_count) {
ml_append(lnum++, ml_append(lnum++,
_("??? from here until ???END lines" _("??? from here until ???END lines"
@@ -1098,13 +1100,27 @@ void ml_recover(bool checkext)
has_error = true; has_error = true;
} }
bool did_questions = false;
for (int i = 0; i < dp->db_line_count; i++) { 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); int txt_start = (dp->db_index[i] & DB_INDEX_MASK);
if (txt_start <= (int)HEADER_SIZE if (txt_start <= (int)HEADER_SIZE
|| txt_start >= (int)dp->db_txt_end) { || txt_start >= (int)dp->db_txt_end) {
p = "???";
error++; error++;
// avoid lots of lines with "???"
if (did_questions) {
continue;
}
did_questions = true;
p = "???";
} else { } else {
did_questions = false;
p = (char *)dp + txt_start; p = (char *)dp + txt_start;
} }
ml_append(lnum++, p, (colnr_T)0, true); ml_append(lnum++, p, (colnr_T)0, true);

View File

@@ -303,6 +303,21 @@ func Test_recover_corrupted_swap_file()
\ '???END'], getline(1, '$')) \ '???END'], getline(1, '$'))
bw! 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 " use an invalid text start for the lines in a data block
let b = copy(save_b) let b = copy(save_b)
if system_64bit if system_64bit