diff options
Diffstat (limited to '')
-rw-r--r-- | src/strings.c | 153 |
1 files changed, 120 insertions, 33 deletions
diff --git a/src/strings.c b/src/strings.c index 0aeea4b..33de175 100644 --- a/src/strings.c +++ b/src/strings.c @@ -942,7 +942,6 @@ string_filter_map( break; len = (int)STRLEN(tv.vval.v_string); - newtv.v_type = VAR_UNKNOWN; set_vim_var_nr(VV_KEY, idx); if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL || did_emsg) @@ -951,7 +950,7 @@ string_filter_map( clear_tv(&tv); break; } - else if (filtermap != FILTERMAP_FILTER) + if (filtermap == FILTERMAP_MAP || filtermap == FILTERMAP_MAPNEW) { if (newtv.v_type != VAR_STRING) { @@ -963,7 +962,7 @@ string_filter_map( else ga_concat(&ga, newtv.vval.v_string); } - else if (!rem) + else if (filtermap == FILTERMAP_FOREACH || !rem) ga_concat(&ga, tv.vval.v_string); clear_tv(&newtv); @@ -2469,6 +2468,55 @@ adjust_types( return OK; } + static void +format_overflow_error(const char *pstart) +{ + size_t arglen = 0; + char *argcopy = NULL; + const char *p = pstart; + + while (VIM_ISDIGIT((int)(*p))) + ++p; + + arglen = p - pstart; + argcopy = ALLOC_CLEAR_MULT(char, arglen + 1); + if (argcopy != NULL) + { + strncpy(argcopy, pstart, arglen); + semsg(_( e_val_too_large), argcopy); + free(argcopy); + } + else + semsg(_(e_out_of_memory_allocating_nr_bytes), arglen); +} + +#define MAX_ALLOWED_STRING_WIDTH 6400 + + static int +get_unsigned_int( + const char *pstart, + const char **p, + unsigned int *uj) +{ + *uj = **p - '0'; + ++*p; + + while (VIM_ISDIGIT((int)(**p)) && *uj < MAX_ALLOWED_STRING_WIDTH) + { + *uj = 10 * *uj + (unsigned int)(**p - '0'); + ++*p; + } + + if (*uj > MAX_ALLOWED_STRING_WIDTH) + { + format_overflow_error(pstart); + return FAIL; + } + + return OK; +} + + static int parse_fmt_types( const char ***ap_types, @@ -2512,6 +2560,7 @@ parse_fmt_types( // variable for positional arg int pos_arg = -1; const char *ptype = NULL; + const char *pstart = p+1; p++; // skip '%' @@ -2532,10 +2581,11 @@ parse_fmt_types( } // Positional argument - unsigned int uj = *p++ - '0'; + unsigned int uj; + + if (get_unsigned_int(pstart, &p, &uj) == FAIL) + goto error; - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); pos_arg = uj; any_pos = 1; @@ -2572,10 +2622,10 @@ parse_fmt_types( if (VIM_ISDIGIT((int)(*p))) { // Positional argument field width - unsigned int uj = *p++ - '0'; + unsigned int uj; - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); + if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) + goto error; if (*p != '$') { @@ -2602,10 +2652,11 @@ parse_fmt_types( { // size_t could be wider than unsigned int; make sure we treat // argument like common implementations do - unsigned int uj = *p++ - '0'; + const char *digstart = p; + unsigned int uj; - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) + goto error; if (*p == '$') { @@ -2626,10 +2677,10 @@ parse_fmt_types( if (VIM_ISDIGIT((int)(*p))) { // Parse precision - unsigned int uj = *p++ - '0'; + unsigned int uj; - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); + if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) + goto error; if (*p == '$') { @@ -2657,10 +2708,11 @@ parse_fmt_types( { // size_t could be wider than unsigned int; make sure we // treat argument like common implementations do - unsigned int uj = *p++ - '0'; + const char *digstart = p; + unsigned int uj; - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) + goto error; if (*p == '$') { @@ -2969,10 +3021,12 @@ vim_vsnprintf_typval( if (*ptype == '$') { // Positional argument - unsigned int uj = *p++ - '0'; + const char *digstart = p; + unsigned int uj; + + if (get_unsigned_int(digstart, &p, &uj) == FAIL) + goto error; - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); pos_arg = uj; ++p; @@ -3003,16 +3057,18 @@ vim_vsnprintf_typval( if (*p == '*') { int j; + const char *digstart = p + 1; p++; if (VIM_ISDIGIT((int)(*p))) { // Positional argument field width - unsigned int uj = *p++ - '0'; + unsigned int uj; + + if (get_unsigned_int(digstart, &p, &uj) == FAIL) + goto error; - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); arg_idx = uj; ++p; @@ -3026,6 +3082,12 @@ vim_vsnprintf_typval( &arg_cur, fmt), va_arg(ap, int)); + if (j > MAX_ALLOWED_STRING_WIDTH) + { + format_overflow_error(digstart); + goto error; + } + if (j >= 0) min_field_width = j; else @@ -3038,10 +3100,18 @@ vim_vsnprintf_typval( { // size_t could be wider than unsigned int; make sure we treat // argument like common implementations do - unsigned int uj = *p++ - '0'; + const char *digstart = p; + unsigned int uj; + + if (get_unsigned_int(digstart, &p, &uj) == FAIL) + goto error; + + if (uj > MAX_ALLOWED_STRING_WIDTH) + { + format_overflow_error(digstart); + goto error; + } - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); min_field_width = uj; } @@ -3055,25 +3125,35 @@ vim_vsnprintf_typval( { // size_t could be wider than unsigned int; make sure we // treat argument like common implementations do - unsigned int uj = *p++ - '0'; + const char *digstart = p; + unsigned int uj; + + if (get_unsigned_int(digstart, &p, &uj) == FAIL) + goto error; + + if (uj > MAX_ALLOWED_STRING_WIDTH) + { + format_overflow_error(digstart); + goto error; + } - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); precision = uj; } else if (*p == '*') { int j; + const char *digstart = p; p++; if (VIM_ISDIGIT((int)(*p))) { // positional argument - unsigned int uj = *p++ - '0'; + unsigned int uj; + + if (get_unsigned_int(digstart, &p, &uj) == FAIL) + goto error; - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); arg_idx = uj; ++p; @@ -3087,6 +3167,12 @@ vim_vsnprintf_typval( &arg_cur, fmt), va_arg(ap, int)); + if (j > MAX_ALLOWED_STRING_WIDTH) + { + format_overflow_error(digstart); + goto error; + } + if (j >= 0) precision = j; else @@ -3874,6 +3960,7 @@ vim_vsnprintf_typval( if (tvs != NULL && tvs[num_posarg != 0 ? num_posarg : arg_idx - 1].v_type != VAR_UNKNOWN) emsg(_(e_too_many_arguments_to_printf)); +error: vim_free((char*)ap_types); va_end(ap); |