mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 03:05:11 -07:00
vim-patch:9.0.2107: [security]: FPE in adjust_plines_for_skipcol (#26082)
Problem: [security]: FPE in adjust_plines_for_skipcol
Solution: don't divide by zero, return zero
Prevent a floating point exception when calculating w_skipcol (which can
happen with a small window when the number option is set and cpo+=n).
Add a test to verify
cb0b99f067
Co-authored-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
133a592d19
commit
6952b1951b
@ -262,9 +262,9 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
|
||||
&& (last < wp->w_topline
|
||||
|| (wp->w_topline >= lnum
|
||||
&& wp->w_topline < lnume
|
||||
&& win_linetabsize(wp, wp->w_topline, ml_get(wp->w_topline), (colnr_T)MAXCOL)
|
||||
<= (unsigned)(wp->w_skipcol + sms_marker_overlap(wp, win_col_off(wp)
|
||||
- win_col_off2(wp)))))) {
|
||||
&& win_linetabsize(wp, wp->w_topline, ml_get(wp->w_topline), MAXCOL)
|
||||
<= (wp->w_skipcol
|
||||
+ sms_marker_overlap(wp, win_col_off(wp) - win_col_off2(wp)))))) {
|
||||
wp->w_skipcol = 0;
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a
|
||||
col = wcol;
|
||||
|
||||
if ((addspaces || finetune) && !VIsual_active) {
|
||||
curwin->w_curswant = (int)linetabsize(curwin, pos->lnum) + one_more;
|
||||
curwin->w_curswant = linetabsize(curwin, pos->lnum) + one_more;
|
||||
if (curwin->w_curswant > 0) {
|
||||
curwin->w_curswant--;
|
||||
}
|
||||
@ -125,7 +125,7 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a
|
||||
&& curwin->w_width_inner != 0
|
||||
&& wcol >= (colnr_T)width
|
||||
&& width > 0) {
|
||||
csize = (int)linetabsize(curwin, pos->lnum);
|
||||
csize = linetabsize(curwin, pos->lnum);
|
||||
if (csize > 0) {
|
||||
csize--;
|
||||
}
|
||||
|
@ -65,8 +65,9 @@ int adjust_plines_for_skipcol(win_T *wp)
|
||||
}
|
||||
|
||||
int width = wp->w_width_inner - win_col_off(wp);
|
||||
if (wp->w_skipcol >= width) {
|
||||
return (wp->w_skipcol - width) / (width + win_col_off2(wp)) + 1;
|
||||
int w2 = width + win_col_off2(wp);
|
||||
if (wp->w_skipcol >= width && w2 > 0) {
|
||||
return (wp->w_skipcol - width) / w2 + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1238,8 +1239,8 @@ bool scrolldown(linenr_T line_count, int byfold)
|
||||
curwin->w_topline = first;
|
||||
} else {
|
||||
if (do_sms) {
|
||||
int size = (int)win_linetabsize(curwin, curwin->w_topline,
|
||||
ml_get(curwin->w_topline), (colnr_T)MAXCOL);
|
||||
int size = win_linetabsize(curwin, curwin->w_topline,
|
||||
ml_get(curwin->w_topline), MAXCOL);
|
||||
if (size > width1) {
|
||||
curwin->w_skipcol = width1;
|
||||
size -= width1;
|
||||
@ -1335,7 +1336,7 @@ bool scrollup(linenr_T line_count, int byfold)
|
||||
if (do_sms || (byfold && hasAnyFolding(curwin)) || win_may_fill(curwin)) {
|
||||
int width1 = curwin->w_width_inner - curwin_col_off();
|
||||
int width2 = width1 + curwin_col_off2();
|
||||
unsigned size = 0;
|
||||
int size = 0;
|
||||
const colnr_T prev_skipcol = curwin->w_skipcol;
|
||||
|
||||
if (do_sms) {
|
||||
@ -1360,7 +1361,7 @@ bool scrollup(linenr_T line_count, int byfold)
|
||||
// the end of the line, then advance to the next line.
|
||||
int add = curwin->w_skipcol > 0 ? width2 : width1;
|
||||
curwin->w_skipcol += add;
|
||||
if ((unsigned)curwin->w_skipcol >= size) {
|
||||
if (curwin->w_skipcol >= size) {
|
||||
if (lnum == curbuf->b_ml.ml_line_count) {
|
||||
// at the last screen line, can't scroll further
|
||||
curwin->w_skipcol -= add;
|
||||
|
@ -2466,7 +2466,7 @@ bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_ar
|
||||
/// @return true if able to move cursor, false otherwise.
|
||||
static bool nv_screengo(oparg_T *oap, int dir, int dist)
|
||||
{
|
||||
int linelen = (int)linetabsize(curwin, curwin->w_cursor.lnum);
|
||||
int linelen = linetabsize(curwin, curwin->w_cursor.lnum);
|
||||
bool retval = true;
|
||||
bool atend = false;
|
||||
int col_off1; // margin offset for first screen line
|
||||
@ -2530,7 +2530,7 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist)
|
||||
}
|
||||
cursor_up_inner(curwin, 1);
|
||||
|
||||
linelen = (int)linetabsize(curwin, curwin->w_cursor.lnum);
|
||||
linelen = linetabsize(curwin, curwin->w_cursor.lnum);
|
||||
if (linelen > width1) {
|
||||
int w = (((linelen - width1 - 1) / width2) + 1) * width2;
|
||||
assert(curwin->w_curswant <= INT_MAX - w);
|
||||
@ -2563,7 +2563,7 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist)
|
||||
if (curwin->w_curswant >= width1) {
|
||||
curwin->w_curswant -= width2;
|
||||
}
|
||||
linelen = (int)linetabsize(curwin, curwin->w_cursor.lnum);
|
||||
linelen = linetabsize(curwin, curwin->w_cursor.lnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5491,7 +5491,7 @@ static void nv_g_cmd(cmdarg_T *cap)
|
||||
case 'M':
|
||||
oap->motion_type = kMTCharWise;
|
||||
oap->inclusive = false;
|
||||
i = (int)linetabsize(curwin, curwin->w_cursor.lnum);
|
||||
i = linetabsize(curwin, curwin->w_cursor.lnum);
|
||||
if (cap->count0 > 0 && cap->count0 <= 100) {
|
||||
coladvance((colnr_T)(i * cap->count0 / 100));
|
||||
} else {
|
||||
|
@ -83,18 +83,18 @@ int linetabsize_col(int startcol, char *s)
|
||||
/// @param len
|
||||
///
|
||||
/// @return Number of characters the string will take on the screen.
|
||||
unsigned win_linetabsize(win_T *wp, linenr_T lnum, char *line, colnr_T len)
|
||||
int win_linetabsize(win_T *wp, linenr_T lnum, char *line, colnr_T len)
|
||||
{
|
||||
chartabsize_T cts;
|
||||
init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
|
||||
win_linetabsize_cts(&cts, len);
|
||||
clear_chartabsize_arg(&cts);
|
||||
return (unsigned)cts.cts_vcol;
|
||||
return cts.cts_vcol;
|
||||
}
|
||||
|
||||
/// Return the number of cells line "lnum" of window "wp" will take on the
|
||||
/// screen, taking into account the size of a tab and inline virtual text.
|
||||
unsigned linetabsize(win_T *wp, linenr_T lnum)
|
||||
int linetabsize(win_T *wp, linenr_T lnum)
|
||||
{
|
||||
return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum), (colnr_T)MAXCOL);
|
||||
}
|
||||
|
@ -1294,9 +1294,7 @@ static bool reg_match_visual(void)
|
||||
rex.line = (uint8_t *)reg_getline(rex.lnum);
|
||||
rex.input = rex.line + col;
|
||||
|
||||
unsigned cols_u = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, (char *)rex.line, col);
|
||||
assert(cols_u <= MAXCOL);
|
||||
colnr_T cols = (colnr_T)cols_u;
|
||||
colnr_T cols = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, (char *)rex.line, col);
|
||||
if (cols < start || cols > end - (*p_sel == 'e')) {
|
||||
return false;
|
||||
}
|
||||
@ -6029,8 +6027,7 @@ static bool regmatch(uint8_t *scan, proftime_T *tm, int *timed_out)
|
||||
break;
|
||||
|
||||
case RE_VCOL:
|
||||
if (!re_num_cmp(win_linetabsize(rex.reg_win == NULL
|
||||
? curwin : rex.reg_win,
|
||||
if (!re_num_cmp((unsigned)win_linetabsize(rex.reg_win == NULL ? curwin : rex.reg_win,
|
||||
rex.reg_firstlnum + rex.lnum,
|
||||
(char *)rex.line,
|
||||
(colnr_T)(rex.input - rex.line)) + 1,
|
||||
@ -14754,9 +14751,9 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
|
||||
result = col > t->state->val * ts;
|
||||
}
|
||||
if (!result) {
|
||||
uintmax_t lts = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, (char *)rex.line, col);
|
||||
int lts = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, (char *)rex.line, col);
|
||||
assert(t->state->val >= 0);
|
||||
result = nfa_re_num_cmp((uintmax_t)t->state->val, op, lts + 1);
|
||||
result = nfa_re_num_cmp((uintmax_t)t->state->val, op, (uintmax_t)lts + 1);
|
||||
}
|
||||
if (result) {
|
||||
add_here = true;
|
||||
|
@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
|
||||
local clear = helpers.clear
|
||||
local exec = helpers.exec
|
||||
local feed = helpers.feed
|
||||
local assert_alive = helpers.assert_alive
|
||||
|
||||
before_each(clear)
|
||||
|
||||
@ -1007,6 +1008,21 @@ describe('smoothscroll', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
-- oldtest: Test_smoothscroll_crash()
|
||||
it('does not crash with small window and cpo+=n', function()
|
||||
screen:try_resize(40, 12)
|
||||
exec([[
|
||||
20 new
|
||||
vsp
|
||||
put =repeat('aaaa', 20)
|
||||
set nu fdc=1 smoothscroll cpo+=n
|
||||
vert resize 0
|
||||
exe "norm! 0\<c-e>"
|
||||
]])
|
||||
feed('2<C-E>')
|
||||
assert_alive()
|
||||
end)
|
||||
|
||||
it("works with virt_lines above and below", function()
|
||||
screen:try_resize(55, 7)
|
||||
exec([=[
|
||||
|
@ -929,4 +929,23 @@ func Test_smoothscroll_cursor_top()
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
" Division by zero, shouldn't crash
|
||||
func Test_smoothscroll_crash()
|
||||
CheckScreendump
|
||||
|
||||
let lines =<< trim END
|
||||
20 new
|
||||
vsp
|
||||
put =repeat('aaaa', 20)
|
||||
set nu fdc=1 smoothscroll cpo+=n
|
||||
vert resize 0
|
||||
exe "norm! 0\<c-e>"
|
||||
END
|
||||
call writefile(lines, 'XSmoothScrollCrash', 'D')
|
||||
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollCrash', #{rows: 12, cols:40})
|
||||
call term_sendkeys(buf, "2\<C-E>\<C-L>")
|
||||
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
Loading…
Reference in New Issue
Block a user