getdigits: introduce strict, def parameters

Problem:
During a refactor long ago, we changed the `getdigits_*` familiy of
functions to abort on overflow.  But this is often wrong, because many
of these codepaths are handling user input.

Solution:
Decide at each call-site whether to use "strict" mode.

fix #5555
This commit is contained in:
Justin M. Keyes 2019-09-13 18:15:09 -07:00
parent 0a24a2c314
commit 3344cffe7b
22 changed files with 150 additions and 113 deletions

View File

@ -1017,7 +1017,7 @@ do_bufdel(
} }
arg = p; arg = p;
} else } else
bnr = getdigits_int(&arg); bnr = getdigits_int(&arg, false, 0);
} }
} }
if (!got_int && do_current if (!got_int && do_current
@ -3626,10 +3626,7 @@ int build_stl_str_hl(
// The first digit group is the item's min width // The first digit group is the item's min width
if (ascii_isdigit(*fmt_p)) { if (ascii_isdigit(*fmt_p)) {
minwid = getdigits_int(&fmt_p); minwid = getdigits_int(&fmt_p, false, 0);
if (minwid < 0) { // overflow
minwid = 0;
}
} }
// User highlight groups override the min width field // User highlight groups override the min width field
@ -3712,10 +3709,7 @@ int build_stl_str_hl(
if (*fmt_p == '.') { if (*fmt_p == '.') {
fmt_p++; fmt_p++;
if (ascii_isdigit(*fmt_p)) { if (ascii_isdigit(*fmt_p)) {
maxwid = getdigits_int(&fmt_p); maxwid = getdigits_int(&fmt_p, false, 50);
if (maxwid <= 0) { // overflow
maxwid = 50;
}
} }
} }

View File

@ -1323,7 +1323,7 @@ int open_line(
if (*p == COM_RIGHT || *p == COM_LEFT) { if (*p == COM_RIGHT || *p == COM_LEFT) {
c = *p++; c = *p++;
} else if (ascii_isdigit(*p) || *p == '-') { } else if (ascii_isdigit(*p) || *p == '-') {
off = getdigits_int(&p); off = getdigits_int(&p, true, 0);
} else { } else {
p++; p++;
} }

View File

@ -166,7 +166,7 @@ int buf_init_chartab(buf_T *buf, int global)
} }
if (ascii_isdigit(*p)) { if (ascii_isdigit(*p)) {
c = getdigits_int((char_u **)&p); c = getdigits_int((char_u **)&p, true, 0);
} else { } else {
c = mb_ptr2char_adv(&p); c = mb_ptr2char_adv(&p);
} }
@ -176,7 +176,7 @@ int buf_init_chartab(buf_T *buf, int global)
++p; ++p;
if (ascii_isdigit(*p)) { if (ascii_isdigit(*p)) {
c2 = getdigits_int((char_u **)&p); c2 = getdigits_int((char_u **)&p, true, 0);
} else { } else {
c2 = mb_ptr2char_adv(&p); c2 = mb_ptr2char_adv(&p);
} }
@ -1595,7 +1595,7 @@ char_u* skiptowhite_esc(char_u *p) {
return p; return p;
} }
/// Get a number from a string and skip over it, signalling overflows /// Gets a number from a string and skips over it, signalling overflow.
/// ///
/// @param[out] pp A pointer to a pointer to char_u. /// @param[out] pp A pointer to a pointer to char_u.
/// It will be advanced past the read number. /// It will be advanced past the read number.
@ -1606,48 +1606,58 @@ bool try_getdigits(char_u **pp, intmax_t *nr)
{ {
errno = 0; errno = 0;
*nr = strtoimax((char *)(*pp), (char **)pp, 10); *nr = strtoimax((char *)(*pp), (char **)pp, 10);
if (errno == ERANGE && (*nr == INTMAX_MIN || *nr == INTMAX_MAX)) {
if ((*nr == INTMAX_MIN || *nr == INTMAX_MAX)
&& errno == ERANGE) {
return false; return false;
} }
return true; return true;
} }
/// Get a number from a string and skip over it. /// Gets a number from a string and skips over it.
/// ///
/// @param[out] pp A pointer to a pointer to char_u. /// @param[out] pp Pointer to a pointer to char_u.
/// It will be advanced past the read number. /// It will be advanced past the read number.
/// @param strict Abort on overflow.
/// @param def Default value, if parsing fails or overflow occurs.
/// ///
/// @return Number read from the string. /// @return Number read from the string, or `def` on parse failure or overflow.
intmax_t getdigits(char_u **pp) intmax_t getdigits(char_u **pp, bool strict, intmax_t def)
{ {
intmax_t number; intmax_t number;
int ok = try_getdigits(pp, &number); int ok = try_getdigits(pp, &number);
if (strict && !ok) {
(void)ok; // Avoid "unused variable" warning in Release build abort();
assert(ok); }
return ok ? number : def;
return number;
} }
/// Get an int number from a string. Like getdigits(), but restricted to `int`. /// Gets an int number from a string.
int getdigits_int(char_u **pp) ///
/// @see getdigits
int getdigits_int(char_u **pp, bool strict, int def)
{ {
intmax_t number = getdigits(pp); intmax_t number = getdigits(pp, strict, def);
#if SIZEOF_INTMAX_T > SIZEOF_INT #if SIZEOF_INTMAX_T > SIZEOF_INT
assert(number >= INT_MIN && number <= INT_MAX); if (strict) {
assert(number >= INT_MIN && number <= INT_MAX);
} else if (!(number >= INT_MIN && number <= INT_MAX)) {
return def;
}
#endif #endif
return (int)number; return (int)number;
} }
/// Get a long number from a string. Like getdigits(), but restricted to `long`. /// Gets a long number from a string.
long getdigits_long(char_u **pp) ///
/// @see getdigits
long getdigits_long(char_u **pp, bool strict, long def)
{ {
intmax_t number = getdigits(pp); intmax_t number = getdigits(pp, strict, def);
#if SIZEOF_INTMAX_T > SIZEOF_LONG #if SIZEOF_INTMAX_T > SIZEOF_LONG
assert(number >= LONG_MIN && number <= LONG_MAX); if (strict) {
assert(number >= LONG_MIN && number <= LONG_MAX);
} else if (!(number >= LONG_MIN && number <= LONG_MAX)) {
return def;
}
#endif #endif
return (long)number; return (long)number;
} }

View File

@ -176,15 +176,17 @@ char_u *parse_shape_opt(int what)
p += len; p += len;
if (!ascii_isdigit(*p)) if (!ascii_isdigit(*p))
return (char_u *)N_("E548: digit expected"); return (char_u *)N_("E548: digit expected");
int n = getdigits_int(&p); int n = getdigits_int(&p, false, 0);
if (len == 3) { /* "ver" or "hor" */ if (len == 3) { /* "ver" or "hor" */
if (n == 0) if (n == 0) {
return (char_u *)N_("E549: Illegal percentage"); return (char_u *)N_("E549: Illegal percentage");
}
if (round == 2) { if (round == 2) {
if (TOLOWER_ASC(i) == 'v') if (TOLOWER_ASC(i) == 'v') {
shape_table[idx].shape = SHAPE_VER; shape_table[idx].shape = SHAPE_VER;
else } else {
shape_table[idx].shape = SHAPE_HOR; shape_table[idx].shape = SHAPE_HOR;
}
shape_table[idx].percentage = n; shape_table[idx].percentage = n;
} }
} else if (round == 2) { } else if (round == 2) {

View File

@ -2113,7 +2113,7 @@ int diffopt_changed(void)
diff_flags_new |= DIFF_FILLER; diff_flags_new |= DIFF_FILLER;
} else if ((STRNCMP(p, "context:", 8) == 0) && ascii_isdigit(p[8])) { } else if ((STRNCMP(p, "context:", 8) == 0) && ascii_isdigit(p[8])) {
p += 8; p += 8;
diff_context_new = getdigits_int(&p); diff_context_new = getdigits_int(&p, false, diff_context_new);
} else if (STRNCMP(p, "iblank", 6) == 0) { } else if (STRNCMP(p, "iblank", 6) == 0) {
p += 6; p += 6;
diff_flags_new |= DIFF_IBLANK; diff_flags_new |= DIFF_IBLANK;
@ -2137,7 +2137,7 @@ int diffopt_changed(void)
diff_flags_new |= DIFF_VERTICAL; diff_flags_new |= DIFF_VERTICAL;
} else if ((STRNCMP(p, "foldcolumn:", 11) == 0) && ascii_isdigit(p[11])) { } else if ((STRNCMP(p, "foldcolumn:", 11) == 0) && ascii_isdigit(p[11])) {
p += 11; p += 11;
diff_foldcolumn_new = getdigits_int(&p); diff_foldcolumn_new = getdigits_int(&p, false, diff_foldcolumn_new);
} else if (STRNCMP(p, "hiddenoff", 9) == 0) { } else if (STRNCMP(p, "hiddenoff", 9) == 0) {
p += 9; p += 9;
diff_flags_new |= DIFF_HIDDEN_OFF; diff_flags_new |= DIFF_HIDDEN_OFF;
@ -3000,10 +3000,10 @@ static int parse_diff_ed(char_u *line,
// append: {first}a{first}[,{last}] // append: {first}a{first}[,{last}]
// delete: {first}[,{last}]d{first} // delete: {first}[,{last}]d{first}
p = line; p = line;
f1 = getdigits(&p); f1 = getdigits(&p, true, 0);
if (*p == ',') { if (*p == ',') {
p++; p++;
l1 = getdigits(&p); l1 = getdigits(&p, true, 0);
} else { } else {
l1 = f1; l1 = f1;
} }
@ -3011,10 +3011,10 @@ static int parse_diff_ed(char_u *line,
return FAIL; // invalid diff format return FAIL; // invalid diff format
} }
difftype = *p++; difftype = *p++;
f2 = getdigits(&p); f2 = getdigits(&p, true, 0);
if (*p == ',') { if (*p == ',') {
p++; p++;
l2 = getdigits(&p); l2 = getdigits(&p, true, 0);
} else { } else {
l2 = f2; l2 = f2;
} }
@ -3056,18 +3056,18 @@ static int parse_diff_unified(char_u *line,
// @@ -oldline,oldcount +newline,newcount @@ // @@ -oldline,oldcount +newline,newcount @@
p = line; p = line;
if (*p++ == '@' && *p++ == '@' && *p++ == ' ' && *p++ == '-') { if (*p++ == '@' && *p++ == '@' && *p++ == ' ' && *p++ == '-') {
oldline = getdigits(&p); oldline = getdigits(&p, true, 0);
if (*p == ',') { if (*p == ',') {
p++; p++;
oldcount = getdigits(&p); oldcount = getdigits(&p, true, 0);
} else { } else {
oldcount = 1; oldcount = 1;
} }
if (*p++ == ' ' && *p++ == '+') { if (*p++ == ' ' && *p++ == '+') {
newline = getdigits(&p); newline = getdigits(&p, true, 0);
if (*p == ',') { if (*p == ',') {
p++; p++;
newcount = getdigits(&p); newcount = getdigits(&p, true, 0);
} else { } else {
newcount = 1; newcount = 1;
} }

View File

@ -1618,7 +1618,7 @@ void putdigraph(char_u *str)
EMSG(_(e_number_exp)); EMSG(_(e_number_exp));
return; return;
} }
int n = getdigits_int(&str); int n = getdigits_int(&str, true, 0);
// If the digraph already exists, replace the result. // If the digraph already exists, replace the result.
dp = (digr_T *)user_digraphs.ga_data; dp = (digr_T *)user_digraphs.ga_data;

View File

@ -2939,7 +2939,7 @@ void ex_lockvar(exarg_T *eap)
if (eap->forceit) if (eap->forceit)
deep = -1; deep = -1;
else if (ascii_isdigit(*arg)) { else if (ascii_isdigit(*arg)) {
deep = getdigits_int(&arg); deep = getdigits_int(&arg, false, -1);
arg = skipwhite(arg); arg = skipwhite(arg);
} }
@ -15775,7 +15775,7 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
yank_type = kMTBlockWise; yank_type = kMTBlockWise;
if (ascii_isdigit(stropt[1])) { if (ascii_isdigit(stropt[1])) {
stropt++; stropt++;
block_len = getdigits_long((char_u **)&stropt) - 1; block_len = getdigits_long((char_u **)&stropt, true, 0) - 1;
stropt--; stropt--;
} }
break; break;

View File

@ -707,7 +707,7 @@ void ex_retab(exarg_T *eap)
save_list = curwin->w_p_list; save_list = curwin->w_p_list;
curwin->w_p_list = 0; /* don't want list mode here */ curwin->w_p_list = 0; /* don't want list mode here */
new_ts = getdigits_int(&(eap->arg)); new_ts = getdigits_int(&(eap->arg), false, -1);
if (new_ts < 0) { if (new_ts < 0) {
EMSG(_(e_positive)); EMSG(_(e_positive));
return; return;
@ -3357,7 +3357,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
// check for a trailing count // check for a trailing count
cmd = skipwhite(cmd); cmd = skipwhite(cmd);
if (ascii_isdigit(*cmd)) { if (ascii_isdigit(*cmd)) {
i = getdigits_long(&cmd); i = getdigits_long(&cmd, true, 0);
if (i <= 0 && !eap->skip && subflags.do_error) { if (i <= 0 && !eap->skip && subflags.do_error) {
EMSG(_(e_zerocount)); EMSG(_(e_zerocount));
return NULL; return NULL;

View File

@ -570,7 +570,7 @@ static int dbg_parsearg(char_u *arg, garray_T *gap)
if (here) { if (here) {
bp->dbg_lnum = curwin->w_cursor.lnum; bp->dbg_lnum = curwin->w_cursor.lnum;
} else if (gap != &prof_ga && ascii_isdigit(*p)) { } else if (gap != &prof_ga && ascii_isdigit(*p)) {
bp->dbg_lnum = getdigits_long(&p); bp->dbg_lnum = getdigits_long(&p, true, 0);
p = skipwhite(p); p = skipwhite(p);
} else { } else {
bp->dbg_lnum = 0; bp->dbg_lnum = 0;

View File

@ -2071,7 +2071,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if ((ea.argt & COUNT) && ascii_isdigit(*ea.arg) if ((ea.argt & COUNT) && ascii_isdigit(*ea.arg)
&& (!(ea.argt & BUFNAME) || *(p = skipdigits(ea.arg)) == NUL && (!(ea.argt & BUFNAME) || *(p = skipdigits(ea.arg)) == NUL
|| ascii_iswhite(*p))) { || ascii_iswhite(*p))) {
n = getdigits_long(&ea.arg); n = getdigits_long(&ea.arg, false, -1);
ea.arg = skipwhite(ea.arg); ea.arg = skipwhite(ea.arg);
if (n <= 0 && !ni && (ea.argt & ZEROR) == 0) { if (n <= 0 && !ni && (ea.argt & ZEROR) == 0) {
errormsg = (char_u *)_(e_zerocount); errormsg = (char_u *)_(e_zerocount);
@ -3797,7 +3797,7 @@ static linenr_T get_address(exarg_T *eap,
default: default:
if (ascii_isdigit(*cmd)) /* absolute line number */ if (ascii_isdigit(*cmd)) /* absolute line number */
lnum = getdigits_long(&cmd); lnum = getdigits_long(&cmd, false, 0);
} }
for (;; ) { for (;; ) {
@ -3832,14 +3832,16 @@ static linenr_T get_address(exarg_T *eap,
} }
} }
if (ascii_isdigit(*cmd)) if (ascii_isdigit(*cmd)) {
i = '+'; /* "number" is same as "+number" */ i = '+'; // "number" is same as "+number"
else } else {
i = *cmd++; i = *cmd++;
if (!ascii_isdigit(*cmd)) /* '+' is '+1', but '+0' is not '+1' */ }
if (!ascii_isdigit(*cmd)) { // '+' is '+1', but '+0' is not '+1'
n = 1; n = 1;
else } else {
n = getdigits(&cmd); n = getdigits(&cmd, true, 0);
}
if (addr_type == ADDR_TABS_RELATIVE) { if (addr_type == ADDR_TABS_RELATIVE) {
EMSG(_(e_invrange)); EMSG(_(e_invrange));
@ -4504,7 +4506,7 @@ static int get_tabpage_arg(exarg_T *eap)
} }
p_save = p; p_save = p;
tab_number = getdigits(&p); tab_number = getdigits(&p, false, tab_number);
if (relative == 0) { if (relative == 0) {
if (STRCMP(p, "$") == 0) { if (STRCMP(p, "$") == 0) {
@ -5179,7 +5181,7 @@ two_count:
return FAIL; return FAIL;
} }
*def = getdigits_long(&p); *def = getdigits_long(&p, true, 0);
*argt |= (ZEROR | NOTADR); *argt |= (ZEROR | NOTADR);
if (p != val + vallen || vallen == 0) { if (p != val + vallen || vallen == 0) {
@ -5196,7 +5198,7 @@ invalid_count:
if (*def >= 0) if (*def >= 0)
goto two_count; goto two_count;
*def = getdigits_long(&p); *def = getdigits_long(&p, true, 0);
if (p != val + vallen) if (p != val + vallen)
goto invalid_count; goto invalid_count;
@ -6832,8 +6834,7 @@ static void ex_tabnext(exarg_T *eap)
if (eap->arg && *eap->arg != NUL) { if (eap->arg && *eap->arg != NUL) {
char_u *p = eap->arg; char_u *p = eap->arg;
char_u *p_save = p; char_u *p_save = p;
tab_number = getdigits(&p, false, 0);
tab_number = getdigits(&p);
if (p == p_save || *p_save == '-' || *p_save == '+' || *p != NUL if (p == p_save || *p_save == '-' || *p_save == '+' || *p != NUL
|| tab_number == 0) { || tab_number == 0) {
// No numbers as argument. // No numbers as argument.
@ -7472,18 +7473,16 @@ static void do_exmap(exarg_T *eap, int isabbrev)
*/ */
static void ex_winsize(exarg_T *eap) static void ex_winsize(exarg_T *eap)
{ {
int w, h; char_u *arg = eap->arg;
char_u *arg = eap->arg; int w = getdigits_int(&arg, false, 10);
char_u *p;
w = getdigits_int(&arg);
arg = skipwhite(arg); arg = skipwhite(arg);
p = arg; char_u *p = arg;
h = getdigits_int(&arg); int h = getdigits_int(&arg, false, 10);
if (*p != NUL && *arg == NUL) if (*p != NUL && *arg == NUL) {
screen_resize(w, h); screen_resize(w, h);
else } else {
EMSG(_("E465: :winsize requires two number arguments")); EMSG(_("E465: :winsize requires two number arguments"));
}
} }
static void ex_wincmd(exarg_T *eap) static void ex_wincmd(exarg_T *eap)
@ -7745,7 +7744,7 @@ static void ex_later(exarg_T *eap)
if (*p == NUL) if (*p == NUL)
count = 1; count = 1;
else if (isdigit(*p)) { else if (isdigit(*p)) {
count = getdigits_long(&p); count = getdigits_long(&p, false, 0);
switch (*p) { switch (*p) {
case 's': ++p; sec = true; break; case 's': ++p; sec = true; break;
case 'm': ++p; sec = true; count *= 60; break; case 'm': ++p; sec = true; count *= 60; break;
@ -8414,7 +8413,7 @@ static void ex_findpat(exarg_T *eap)
n = 1; n = 1;
if (ascii_isdigit(*eap->arg)) { /* get count */ if (ascii_isdigit(*eap->arg)) { /* get count */
n = getdigits_long(&eap->arg); n = getdigits_long(&eap->arg, false, 0);
eap->arg = skipwhite(eap->arg); eap->arg = skipwhite(eap->arg);
} }
if (*eap->arg == '/') { /* Match regexp, not just whole words */ if (*eap->arg == '/') { /* Match regexp, not just whole words */
@ -8660,13 +8659,13 @@ eval_vars (
return NULL; return NULL;
} }
} }
/* //
* '#': Alternate file name // '#': Alternate file name
* '%': Current file name // '%': Current file name
* File name under the cursor // File name under the cursor
* File name for autocommand // File name for autocommand
* and following modifiers // and following modifiers
*/ //
else { else {
switch (spec_idx) { switch (spec_idx) {
case SPEC_PERC: /* '%': current file */ case SPEC_PERC: /* '%': current file */
@ -8692,7 +8691,7 @@ eval_vars (
s = src + 1; s = src + 1;
if (*s == '<') /* "#<99" uses v:oldfiles */ if (*s == '<') /* "#<99" uses v:oldfiles */
++s; ++s;
i = getdigits_int(&s); i = getdigits_int(&s, false, 0);
if (s == src + 2 && src[1] == '-') { if (s == src + 2 && src[1] == '-') {
// just a minus sign, don't skip over it // just a minus sign, don't skip over it
s--; s--;

View File

@ -325,7 +325,7 @@ static char_u *parse_list_options(char_u *option_str, option_table_T *table,
break; break;
} }
table[idx].number = getdigits_int(&p); table[idx].number = getdigits_int(&p, false, 0);
} }
table[idx].string = p; table[idx].string = p;

View File

@ -1678,7 +1678,7 @@ void parse_cino(buf_T *buf)
if (*p == '-') if (*p == '-')
++p; ++p;
char_u *digits_start = p; /* remember where the digits start */ char_u *digits_start = p; /* remember where the digits start */
int n = getdigits_int(&p); int n = getdigits_int(&p, true, 0);
divider = 0; divider = 0;
if (*p == '.') { /* ".5s" means a fraction */ if (*p == '.') { /* ".5s" means a fraction */
fraction = atoi((char *)++p); fraction = atoi((char *)++p);
@ -1915,7 +1915,7 @@ int get_c_indent(void)
else if (*p == COM_LEFT || *p == COM_RIGHT) else if (*p == COM_LEFT || *p == COM_RIGHT)
align = *p++; align = *p++;
else if (ascii_isdigit(*p) || *p == '-') { else if (ascii_isdigit(*p) || *p == '-') {
off = getdigits_int(&p); off = getdigits_int(&p, true, 0);
} }
else else
++p; ++p;

View File

@ -113,7 +113,7 @@ ex_menu(exarg_T *eap)
} }
if (ascii_iswhite(*p)) { if (ascii_iswhite(*p)) {
for (i = 0; i < MENUDEPTH && !ascii_iswhite(*arg); ++i) { for (i = 0; i < MENUDEPTH && !ascii_iswhite(*arg); ++i) {
pri_tab[i] = getdigits_long(&arg); pri_tab[i] = getdigits_long(&arg, false, 0);
if (pri_tab[i] == 0) if (pri_tab[i] == 0)
pri_tab[i] = 500; pri_tab[i] = 500;
if (*arg == '.') if (*arg == '.')

View File

@ -5714,7 +5714,7 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines)
return false; return false;
} }
const char *p = regtype.data+1; const char *p = regtype.data+1;
reg->y_width = getdigits_int((char_u **)&p)-1; reg->y_width = getdigits_int((char_u **)&p, false, 1) - 1;
if (regtype.size > (size_t)(p-regtype.data)) { if (regtype.size > (size_t)(p-regtype.data)) {
return false; return false;
} }

View File

@ -1585,7 +1585,7 @@ int do_set(
*/ */
else if (varp == (char_u *)&p_bs else if (varp == (char_u *)&p_bs
&& ascii_isdigit(**(char_u **)varp)) { && ascii_isdigit(**(char_u **)varp)) {
i = getdigits_int((char_u **)varp); i = getdigits_int((char_u **)varp, true, 0);
switch (i) { switch (i) {
case 0: case 0:
*(char_u **)varp = empty_option; *(char_u **)varp = empty_option;
@ -1613,7 +1613,7 @@ int do_set(
else if (varp == (char_u *)&p_ww else if (varp == (char_u *)&p_ww
&& ascii_isdigit(*arg)) { && ascii_isdigit(*arg)) {
*errbuf = NUL; *errbuf = NUL;
i = getdigits_int(&arg); i = getdigits_int(&arg, true, 0);
if (i & 1) { if (i & 1) {
STRCAT(errbuf, "b,"); STRCAT(errbuf, "b,");
} }
@ -3053,7 +3053,7 @@ ambw_end:
if (*++s == '-') { // ignore a '-' if (*++s == '-') { // ignore a '-'
s++; s++;
} }
wid = getdigits_int(&s); wid = getdigits_int(&s, true, 0);
if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL) { if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL) {
ru_wid = wid; ru_wid = wid;
} else { } else {
@ -3440,7 +3440,7 @@ char_u *check_colorcolumn(win_T *wp)
if (!ascii_isdigit(*s)) { if (!ascii_isdigit(*s)) {
return e_invarg; return e_invarg;
} }
col = col * getdigits_int(&s); col = col * getdigits_int(&s, true, 0);
if (wp->w_buffer->b_p_tw == 0) { if (wp->w_buffer->b_p_tw == 0) {
goto skip; // 'textwidth' not set, skip this item goto skip; // 'textwidth' not set, skip this item
} }
@ -3455,7 +3455,7 @@ char_u *check_colorcolumn(win_T *wp)
goto skip; goto skip;
} }
} else if (ascii_isdigit(*s)) { } else if (ascii_isdigit(*s)) {
col = getdigits_int(&s); col = getdigits_int(&s, true, 0);
} else { } else {
return e_invarg; return e_invarg;
} }
@ -7109,12 +7109,12 @@ static bool briopt_check(win_T *wp)
&& ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6])))
{ {
p += 6; p += 6;
bri_shift = getdigits_int(&p); bri_shift = getdigits_int(&p, true, 0);
} }
else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4])) else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4]))
{ {
p += 4; p += 4;
bri_min = getdigits_int(&p); bri_min = getdigits_int(&p, true, 0);
} }
else if (STRNCMP(p, "sbr", 3) == 0) else if (STRNCMP(p, "sbr", 3) == 0)
{ {

View File

@ -3110,10 +3110,10 @@ static int read_limits(long *minval, long *maxval)
reverse = TRUE; reverse = TRUE;
} }
first_char = regparse; first_char = regparse;
*minval = getdigits_long(&regparse); *minval = getdigits_long(&regparse, false, 0);
if (*regparse == ',') { /* There is a comma */ if (*regparse == ',') { /* There is a comma */
if (ascii_isdigit(*++regparse)) if (ascii_isdigit(*++regparse))
*maxval = getdigits_long(&regparse); *maxval = getdigits_long(&regparse, false, MAX_LIMIT);
else else
*maxval = MAX_LIMIT; *maxval = MAX_LIMIT;
} else if (ascii_isdigit(*first_char)) } else if (ascii_isdigit(*first_char))

View File

@ -1130,7 +1130,7 @@ static int parse_sign_cmd_args(
// first arg could be placed sign id // first arg could be placed sign id
arg1 = arg; arg1 = arg;
if (ascii_isdigit(*arg)) { if (ascii_isdigit(*arg)) {
*signid = getdigits_int(&arg); *signid = getdigits_int(&arg, true, 0);
if (!ascii_iswhite(*arg) && *arg != NUL) { if (!ascii_iswhite(*arg) && *arg != NUL) {
*signid = -1; *signid = -1;
arg = arg1; arg = arg1;
@ -1182,7 +1182,7 @@ static int parse_sign_cmd_args(
} else if (STRNCMP(arg, "buffer=", 7) == 0) { } else if (STRNCMP(arg, "buffer=", 7) == 0) {
arg += 7; arg += 7;
filename = arg; filename = arg;
*buf = buflist_findnr(getdigits_int(&arg)); *buf = buflist_findnr(getdigits_int(&arg, true, 0));
if (*skipwhite(arg) != NUL) { if (*skipwhite(arg) != NUL) {
EMSG(_(e_trailing)); EMSG(_(e_trailing));
} }

View File

@ -2706,7 +2706,7 @@ int spell_check_sps(void)
f = 0; f = 0;
if (ascii_isdigit(*buf)) { if (ascii_isdigit(*buf)) {
s = buf; s = buf;
sps_limit = getdigits_int(&s); sps_limit = getdigits_int(&s, true, 0);
if (*s != NUL && !ascii_isdigit(*s)) if (*s != NUL && !ascii_isdigit(*s))
f = -1; f = -1;
} else if (STRCMP(buf, "best") == 0) } else if (STRCMP(buf, "best") == 0)

View File

@ -1833,19 +1833,19 @@ int spell_check_msm(void)
if (!ascii_isdigit(*p)) if (!ascii_isdigit(*p))
return FAIL; return FAIL;
// block count = (value * 1024) / SBLOCKSIZE (but avoid overflow) // block count = (value * 1024) / SBLOCKSIZE (but avoid overflow)
start = (getdigits_long(&p) * 10) / (SBLOCKSIZE / 102); start = (getdigits_long(&p, true, 0) * 10) / (SBLOCKSIZE / 102);
if (*p != ',') if (*p != ',')
return FAIL; return FAIL;
++p; ++p;
if (!ascii_isdigit(*p)) if (!ascii_isdigit(*p))
return FAIL; return FAIL;
incr = (getdigits_long(&p) * 102) / (SBLOCKSIZE / 10); incr = (getdigits_long(&p, true, 0) * 102) / (SBLOCKSIZE / 10);
if (*p != ',') if (*p != ',')
return FAIL; return FAIL;
++p; ++p;
if (!ascii_isdigit(*p)) if (!ascii_isdigit(*p))
return FAIL; return FAIL;
added = getdigits_long(&p) * 1024; added = getdigits_long(&p, true, 0) * 1024;
if (*p != NUL) if (*p != NUL)
return FAIL; return FAIL;
@ -2787,7 +2787,7 @@ static unsigned get_affitem(int flagtype, char_u **pp)
++*pp; // always advance, avoid getting stuck ++*pp; // always advance, avoid getting stuck
return 0; return 0;
} }
res = getdigits_int(pp); res = getdigits_int(pp, true, 0);
} else { } else {
res = mb_ptr2char_adv((const char_u **)pp); res = mb_ptr2char_adv((const char_u **)pp);
if (flagtype == AFT_LONG || (flagtype == AFT_CAPLONG if (flagtype == AFT_LONG || (flagtype == AFT_CAPLONG
@ -2906,7 +2906,7 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
case AFT_NUM: case AFT_NUM:
for (p = afflist; *p != NUL; ) { for (p = afflist; *p != NUL; ) {
int digits = getdigits_int(&p); int digits = getdigits_int(&p, true, 0);
assert(digits >= 0); assert(digits >= 0);
n = (unsigned int)digits; n = (unsigned int)digits;
if (n == flag) if (n == flag)

View File

@ -5038,7 +5038,7 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
ci->sp_off_flags |= (1 << idx); ci->sp_off_flags |= (1 << idx);
if (idx == SPO_LC_OFF) { /* lc=99 */ if (idx == SPO_LC_OFF) { /* lc=99 */
end += 3; end += 3;
*p = getdigits_int(&end); *p = getdigits_int(&end, true, 0);
/* "lc=" offset automatically sets "ms=" offset */ /* "lc=" offset automatically sets "ms=" offset */
if (!(ci->sp_off_flags & (1 << SPO_MS_OFF))) { if (!(ci->sp_off_flags & (1 << SPO_MS_OFF))) {
@ -5049,10 +5049,10 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
end += 4; end += 4;
if (*end == '+') { if (*end == '+') {
++end; ++end;
*p = getdigits_int(&end); /* positive offset */ *p = getdigits_int(&end, true, 0); // positive offset
} else if (*end == '-') { } else if (*end == '-') {
++end; ++end;
*p = -getdigits_int(&end); /* negative offset */ *p = -getdigits_int(&end, true, 0); // negative offset
} }
} }
if (*end != ',') if (*end != ',')
@ -5118,7 +5118,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
illegal = TRUE; illegal = TRUE;
break; break;
} }
n = getdigits_long(&arg_end); n = getdigits_long(&arg_end, false, 0);
if (!eap->skip) { if (!eap->skip) {
if (key[4] == 'B') if (key[4] == 'B')
curwin->w_s->b_syn_sync_linebreaks = n; curwin->w_s->b_syn_sync_linebreaks = n;

View File

@ -5982,7 +5982,7 @@ file_name_in_line (
++p; /* skip the separator */ ++p; /* skip the separator */
p = skipwhite(p); p = skipwhite(p);
if (isdigit(*p)) if (isdigit(*p))
*file_lnum = getdigits_long(&p); *file_lnum = getdigits_long(&p, false, 0);
} }
} }

View File

@ -0,0 +1,32 @@
local helpers = require("test.functional.helpers")(after_each)
local command = helpers.command
local eq = helpers.eq
local clear = helpers.clear
local pcall_err = helpers.pcall_err
local assert_alive = helpers.assert_alive
describe('Ex cmds', function()
before_each(function()
clear()
end)
it('handle integer overflow from user-input #5555', function()
command(':9999999999999999999999999999999999999999')
command(':later 9999999999999999999999999999999999999999')
command(':echo expand("#<9999999999999999999999999999999999999999")')
command(':lockvar 9999999999999999999999999999999999999999')
command(':winsize 9999999999999999999999999999999999999999 9999999999999999999999999999999999999999')
eq('Vim(tabnext):E474: Invalid argument',
pcall_err(command, ':tabnext 9999999999999999999999999999999999999999'))
eq('Vim(Next):E939: Positive count required',
pcall_err(command, ':N 9999999999999999999999999999999999999999'))
eq('Vim(menu):E329: No menu "9999999999999999999999999999999999999999"',
pcall_err(command, ':menu 9999999999999999999999999999999999999999'))
eq('Vim(bdelete):E939: Positive count required',
pcall_err(command, ':bdelete 9999999999999999999999999999999999999999'))
eq('Vim(retab):E487: Argument must be positive',
pcall_err(command, ':retab 9999999999999999999999999999999999999999'))
assert_alive()
end)
end)