fix(move): avoid integer overflow with large 'scrolloff' (#39251)

This commit is contained in:
zeertzjq
2026-04-21 07:22:54 +08:00
committed by GitHub
parent 2287c37486
commit 901b3f0c39
6 changed files with 39 additions and 37 deletions

View File

@@ -439,7 +439,7 @@ bool set_leftcol(colnr_T leftcol)
bool retval = false;
// If the cursor is right or left of the screen, move it to last or first
// visible character.
int siso = get_sidescrolloff_value(curwin);
int64_t siso = get_sidescrolloff_value(curwin);
if (curwin->w_virtcol > (colnr_T)(lastcol - siso)) {
retval = true;
coladvance(curwin, (colnr_T)(lastcol - siso));

View File

@@ -6259,7 +6259,7 @@ static void ex_syncbind(exarg_T *eap)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_p_scb && wp->w_buffer) {
linenr_T y = plines_m_win_fill(wp, 1, wp->w_buffer->b_ml.ml_line_count)
- get_scrolloff_value(curwin);
- (int)get_scrolloff_value(curwin);
vtopline = MIN(vtopline, y);
}
}

View File

@@ -407,7 +407,7 @@ void update_topline(win_T *wp)
}
}
if (check_botline) {
int n = 0;
int64_t n = 0;
if (win_lines_concealed(wp)) {
// Count the number of logical lines between the cursor and
// botline - p_so (approximation of how much will be
@@ -421,7 +421,7 @@ void update_topline(win_T *wp)
hasFolding(wp, lnum, &lnum, NULL);
}
} else {
n = wp->w_cursor.lnum - wp->w_botline + 1 + (int)(*so_ptr);
n = wp->w_cursor.lnum - wp->w_botline + 1 + *so_ptr;
}
if (n <= wp->w_view_height + 1) {
scroll_cursor_bot(wp, scrolljump_value(wp), false);
@@ -469,7 +469,7 @@ static int scrolljump_value(win_T *wp)
/// Return true when there are not 'scrolloff' lines above the cursor for window "wp".
static bool check_top_offset(win_T *wp)
{
int so = get_scrolloff_value(wp);
int64_t so = get_scrolloff_value(wp);
if (wp->w_cursor.lnum < wp->w_topline + so || win_lines_concealed(wp)) {
lineoff_T loff;
loff.lnum = wp->w_cursor.lnum;
@@ -888,11 +888,11 @@ void curs_columns(win_T *wp, int may_scroll)
// If Cursor is right of the screen, scroll leftwards
// If we get closer to the edge than 'sidescrolloff', scroll a little
// extra
int siso = get_sidescrolloff_value(wp);
int off_left = startcol - wp->w_leftcol - siso;
int off_right = endcol - wp->w_leftcol - wp->w_view_width + siso + 1;
int64_t siso = get_sidescrolloff_value(wp);
int64_t off_left = startcol - wp->w_leftcol - siso;
int64_t off_right = endcol - wp->w_leftcol - (wp->w_view_width - siso) + 1;
if (off_left < 0 || off_right > 0) {
int diff = (off_left < 0) ? -off_left : off_right;
int64_t diff = (off_left < 0) ? -off_left : off_right;
// When far off or not enough room on either side, put cursor in
// middle of window.
@@ -902,12 +902,12 @@ void curs_columns(win_T *wp, int may_scroll)
} else {
if (diff < p_ss) {
assert(p_ss <= INT_MAX);
diff = (int)p_ss;
diff = p_ss;
}
if (off_left < 0) {
new_leftcol = wp->w_leftcol - diff;
new_leftcol = wp->w_leftcol - (int)diff;
} else {
new_leftcol = wp->w_leftcol + diff;
new_leftcol = wp->w_leftcol + (int)diff;
}
}
new_leftcol = MAX(new_leftcol, 0);
@@ -934,7 +934,7 @@ void curs_columns(win_T *wp, int may_scroll)
}
int plines = 0;
int so = get_scrolloff_value(wp);
int64_t so = get_scrolloff_value(wp);
colnr_T prev_skipcol = wp->w_skipcol;
if ((wp->w_wrow >= wp->w_view_height
|| ((prev_skipcol > 0
@@ -962,8 +962,8 @@ void curs_columns(win_T *wp, int may_scroll)
}
plines--;
if (plines > wp->w_wrow + so) {
assert(so <= INT_MAX);
n = wp->w_wrow + so;
assert(wp->w_wrow + so <= INT_MAX);
n = (int)(wp->w_wrow + so);
} else {
n = plines;
}
@@ -988,7 +988,8 @@ void curs_columns(win_T *wp, int may_scroll)
} else if (extra == 1) {
// less than 'scrolloff' lines above, decrease skipcol
assert(so <= INT_MAX);
extra = (wp->w_skipcol + so * width2 - wp->w_virtcol + width2 - 1) / width2;
extra = (int)((wp->w_skipcol + so * width2 - wp->w_virtcol
+ width2 - 1) / width2);
if (extra > 0) {
if ((colnr_T)(extra * width2) > wp->w_skipcol) {
extra = wp->w_skipcol / width2;
@@ -1212,10 +1213,10 @@ static void cursor_correct_sms(win_T *wp)
return;
}
int so = get_scrolloff_value(wp);
int64_t so = get_scrolloff_value(wp);
int width1 = wp->w_view_width - win_col_off(wp);
int width2 = width1 + win_col_off2(wp);
int so_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
int64_t so_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
int space_cols = (wp->w_view_height - 1) * width2;
int size = so == 0 ? 0 : linetabsize_eol(wp, wp->w_topline);
@@ -1236,8 +1237,8 @@ static void cursor_correct_sms(win_T *wp)
int overlap = wp->w_skipcol == 0
? 0 : sms_marker_overlap(wp, wp->w_view_width - width2);
// If we have non-zero scrolloff, ignore marker overlap.
int top = wp->w_skipcol + (so_cols != 0 ? so_cols : overlap);
int bot = wp->w_skipcol + width1 + (wp->w_view_height - 1) * width2 - so_cols;
int64_t top = wp->w_skipcol + (so_cols != 0 ? so_cols : overlap);
int64_t bot = wp->w_skipcol + width1 + (wp->w_view_height - 1) * width2 - so_cols;
validate_virtcol(wp);
colnr_T col = wp->w_virtcol;
@@ -1564,8 +1565,8 @@ void adjust_skipcol(void)
return; // no text will be displayed
}
int width2 = width1 + win_col_off2(curwin);
int so = get_scrolloff_value(curwin);
colnr_T scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
int64_t so = get_scrolloff_value(curwin);
int64_t scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
bool scrolled = false;
validate_cheight(curwin);
@@ -1596,7 +1597,7 @@ void adjust_skipcol(void)
return; // don't scroll in the other direction now
}
int row = 0;
colnr_T col = curwin->w_virtcol + scrolloff_cols;
int64_t col = curwin->w_virtcol + scrolloff_cols;
// Avoid adjusting for 'scrolloff' beyond the text line height.
if (scrolloff_cols > 0) {
@@ -1613,7 +1614,7 @@ void adjust_skipcol(void)
row++;
}
if (col > width2) {
row += (int)col / width2;
row += (int)(col / width2);
}
if (row >= curwin->w_view_height) {
if (curwin->w_skipcol == 0) {
@@ -1785,7 +1786,7 @@ void scroll_cursor_top(win_T *wp, int min_scroll, int always)
linenr_T old_topline = wp->w_topline;
int old_skipcol = wp->w_skipcol;
linenr_T old_topfill = wp->w_topfill;
int off = get_scrolloff_value(wp);
int64_t off = get_scrolloff_value(wp);
if (mouse_dragging > 0) {
off = mouse_dragging - 1;
@@ -1861,7 +1862,7 @@ void scroll_cursor_top(win_T *wp, int min_scroll, int always)
wp->w_topline = MIN(wp->w_topline, wp->w_cursor.lnum);
wp->w_topfill = win_get_fill(wp, wp->w_topline);
if (wp->w_topfill > 0 && extra > off) {
wp->w_topfill -= extra - off;
wp->w_topfill -= extra - (int)off;
wp->w_topfill = MAX(wp->w_topfill, 0);
}
check_topfill(wp, false);
@@ -2027,7 +2028,7 @@ void scroll_cursor_bot(win_T *wp, int min_scroll, bool set_topbot)
int fill_below_window = win_get_fill(wp, wp->w_botline) - wp->w_filler_rows;
int extra = 0;
int so = get_scrolloff_value(wp);
int64_t so = get_scrolloff_value(wp);
while (loff.lnum > 1) {
// Stop when scrolled nothing or at least "min_scroll", found "extra"
// context for 'scrolloff' and counted all lines below the window.
@@ -2275,8 +2276,8 @@ void cursor_correct(win_T *wp)
{
// How many lines we would like to have above/below the cursor depends on
// whether the first/last line of the file is on screen.
int above_wanted = get_scrolloff_value(wp);
int below_wanted = get_scrolloff_value(wp);
int64_t above_wanted = get_scrolloff_value(wp);
int64_t below_wanted = get_scrolloff_value(wp);
if (mouse_dragging > 0) {
above_wanted = mouse_dragging - 1;
below_wanted = mouse_dragging - 1;

View File

@@ -2769,7 +2769,7 @@ static void nv_zet(cmdarg_T *cap)
int old_fdl = (int)curwin->w_p_fdl;
int old_fen = curwin->w_p_fen;
int siso = get_sidescrolloff_value(curwin);
int64_t siso = get_sidescrolloff_value(curwin);
if (ascii_isdigit(nchar) && !nv_z_get_count(cap, &nchar)) {
return;
@@ -2890,7 +2890,7 @@ static void nv_zet(cmdarg_T *cap)
getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL, 0);
}
if (col > siso) {
col -= siso;
col -= (int)siso;
} else {
col = 0;
}
@@ -2913,7 +2913,8 @@ static void nv_zet(cmdarg_T *cap)
if (col + siso < n) {
col = 0;
} else {
col = col + siso - n + 1;
// TODO(zeertzjq): check for overflow
col = (int)(col + siso - n + 1);
}
if (curwin->w_leftcol != col) {
curwin->w_leftcol = col;

View File

@@ -6550,21 +6550,21 @@ dict_T *get_winbuf_options(const int bufopt)
/// Return the effective 'scrolloff' value for the current window, using the
/// global value when appropriate.
int get_scrolloff_value(win_T *wp)
int64_t get_scrolloff_value(win_T *wp)
{
// Disallow scrolloff in terminal-mode. #11915
// Still allow 'scrolloff' for non-terminal buffers. #34447
if ((State & MODE_TERMINAL) && wp->w_buffer->terminal) {
return 0;
}
return (int)(wp->w_p_so < 0 ? p_so : wp->w_p_so);
return wp->w_p_so < 0 ? p_so : wp->w_p_so;
}
/// Return the effective 'sidescrolloff' value for the current window, using the
/// global value when appropriate.
int get_sidescrolloff_value(win_T *wp)
int64_t get_sidescrolloff_value(win_T *wp)
{
return (int)(wp->w_p_siso < 0 ? p_siso : wp->w_p_siso);
return wp->w_p_siso < 0 ? p_siso : wp->w_p_siso;
}
Dict get_vimoption(String name, int opt_flags, buf_T *buf, win_T *win, Arena *arena, Error *err)

View File

@@ -6868,7 +6868,7 @@ static void win_fix_cursor(bool normal)
wp->w_do_win_fix_cursor = false;
// Determine valid cursor range.
int so = MIN(wp->w_view_height / 2, get_scrolloff_value(wp));
int so = (int)MIN(wp->w_view_height / 2, get_scrolloff_value(wp));
linenr_T lnum = wp->w_cursor.lnum;
wp->w_cursor.lnum = wp->w_topline;