From 134782b99effbbed5f1fdba6e547c38e39204c4a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 19 Feb 2026 08:06:39 +0800 Subject: [PATCH 1/2] vim-patch:9.2.0023: fix integer overflow in ml_append_int() for long lines Problem: ml_append_int() crashes when appending lines near MAXCOL length due to signed integer overflow in space_needed calculation. Solution: Change 'space_needed' from int to long to handle the 'len + INDEX_SIZE' computation without overflow. Update db_free comparison casts from (int) to (long) to match. Note: supported by AI claude related: vim/vim#17935 related: vim/vim#18953 related: vim/vim#19332 https://github.com/vim/vim/commit/0ece393844a4433e4dc69cde6fe88f99ed7db100 Co-authored-by: Christian Brabandt --- src/nvim/memline.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/nvim/memline.c b/src/nvim/memline.c index e620cd8539..519aa6cc59 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -2000,10 +2000,10 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line_arg, colnr_T len_ if (len == 0) { len = (colnr_T)strlen(line) + 1; // space needed for the text } - int space_needed = len + (int)INDEX_SIZE; // space needed for text + index + int64_t space_needed = len + (int64_t)INDEX_SIZE; // space needed for text + index memfile_T *mfp = buf->b_ml.ml_mfp; - int page_size = (int)mfp->mf_page_size; + int64_t page_size = mfp->mf_page_size; // find the data block containing the previous line // This also fills the stack with the blocks from the root to the data block @@ -2033,7 +2033,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line_arg, colnr_T len_ // - appending to the last line in the block // - not appending to the last line in the file // insert in front of the next block. - if ((int)dp->db_free < space_needed && db_idx == line_count - 1 + if ((int64_t)dp->db_free < space_needed && db_idx == line_count - 1 && lnum < buf->b_ml.ml_line_count) { // Now that the line is not going to be inserted in the block that we // expected, the line count has to be adjusted in the pointer blocks @@ -2057,7 +2057,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line_arg, colnr_T len_ } buf->b_ml.ml_line_count++; - if ((int)dp->db_free >= space_needed) { // enough room in data block + if ((int64_t)dp->db_free >= space_needed) { // enough room in data block // Insert the new line in an existing data block, or in the data block // allocated above. dp->db_txt_start -= (unsigned)len; @@ -2135,7 +2135,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line_arg, colnr_T len_ data_moved = (int)(((dp->db_index[db_idx]) & DB_INDEX_MASK) - dp->db_txt_start); total_moved = data_moved + lines_moved * (int)INDEX_SIZE; - if ((int)dp->db_free + total_moved >= space_needed) { + if ((int64_t)dp->db_free + total_moved >= space_needed) { in_left = true; // put new line in left block space_needed = total_moved; } else { @@ -2145,7 +2145,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line_arg, colnr_T len_ } } - int page_count = ((space_needed + (int)HEADER_SIZE) + page_size - 1) / page_size; + int64_t page_count = ((space_needed + (int64_t)HEADER_SIZE) + page_size - 1) / page_size; hp_new = ml_new_data(mfp, flags & ML_APPEND_NEW, page_count); if (db_idx < 0) { // left block is new hp_left = hp_new; @@ -2939,7 +2939,7 @@ static void ml_flush_line(buf_T *buf, bool noalloc) } /// create a new, empty, data block -static bhdr_T *ml_new_data(memfile_T *mfp, bool negative, int page_count) +static bhdr_T *ml_new_data(memfile_T *mfp, bool negative, int64_t page_count) { assert(page_count >= 0); bhdr_T *hp = mf_new(mfp, negative, (unsigned)page_count); From fadf5fc8dbf936c22d0905f4e29577b490382b8f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 19 Feb 2026 08:16:11 +0800 Subject: [PATCH 2/2] vim-patch:9.2.0024: Reading files with very long lines crashes with a segfault Problem: Reading files with lines approaching MAXCOL length crashes with segfault due to colnr_T overflow. Solution: The split check 'linerest >= MAXCOL' fired too late because linerest could grow by up to 'size' bytes before the next check. Change threshold to 'linerest >= MAXCOL - size' to ensure the line passed to ml_append() stays within colnr_T range. Note: supported by AI claude fixes: vim/vim#17935 closes: vim/vim#18953 closes: vim/vim#19332 https://github.com/vim/vim/commit/6cc291da063e7d9a74a6337d6a80af2b3bcbb5a9 Co-authored-by: Christian Brabandt --- src/nvim/fileio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 9389d866d3..f4217c5e60 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -892,7 +892,12 @@ retry: } // Protect against the argument of lalloc() going negative. - if (size < 0 || size + linerest + 1 < 0 || linerest >= MAXCOL) { + // Also split lines that are too long for colnr_T. After this check + // passes, we read up to 'size' more bytes. We must ensure that even + // after that read, the line length won't exceed MAXCOL - 1 (because + // we add 1 for the NUL when casting to colnr_T). If this check fires, + // we insert a synthetic newline immediately, so linerest doesn't grow. + if (size < 0 || size + linerest + 1 < 0 || linerest >= MAXCOL - size) { split++; *ptr = NL; // split line by inserting a NL size = 1;