summaryrefslogtreecommitdiffstats
path: root/src/strings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/strings.c')
-rw-r--r--src/strings.c153
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);