diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-11-05 20:11:06 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-11-05 20:11:06 +0200 |
commit | 753987210e9e136b59d433c8293a856e98826ee9 (patch) | |
tree | 648dd7fd4646cf7fc8c6304d8049e2e6f6f2d78e /src | |
parent | e337b4120f2961b9b9c11a09a23a50fc4416502d (diff) | |
download | mailfromd-753987210e9e136b59d433c8293a856e98826ee9.tar.gz mailfromd-753987210e9e136b59d433c8293a856e98826ee9.tar.bz2 |
Improve numeric overflow checking during stack/data reallocation
* src/gram.y (strtosize): Improve numeric overflow checking.
* src/prog.c (expand_dataseg): Change signature. Improve
reallocation strategy and overflow checking. Don't throw exception
on error, that's the responsibility of the caller.
All uses changed.
* src/prog.h (expand_dataseg): Change signature.
* src/builtin/debug.bi (_expand_dataseg): Update call to expand_dataseg.
Diffstat (limited to 'src')
-rw-r--r-- | src/builtin/debug.bi | 5 | ||||
-rw-r--r-- | src/gram.y | 29 | ||||
-rw-r--r-- | src/prog.c | 77 | ||||
-rw-r--r-- | src/prog.h | 2 |
4 files changed, 61 insertions, 52 deletions
diff --git a/src/builtin/debug.bi b/src/builtin/debug.bi index 655e8c88..e53a1b61 100644 --- a/src/builtin/debug.bi +++ b/src/builtin/debug.bi @@ -105,8 +105,9 @@ END MF_DEFUN(_expand_dataseg, VOID, NUMBER words) { - expand_dataseg(env, words, - _("out of stack space; increase #pragma stacksize")); + MF_ASSERT(expand_dataseg(env, words) == 0, + mfe_failure, + _("out of stack space; increase #pragma stacksize")); } END @@ -21,6 +21,7 @@ #include <fnmatch.h> #include <netdb.h> +#include <limits.h> #include "mailfromd.h" #include <mailutils/yyloc.h> #include "prog.h" @@ -3297,31 +3298,36 @@ pragma_regex(int argc, char **argv, const char *text) static int strtosize(const char *text, size_t *psize) { - unsigned long n; - size_t size; + unsigned long size; + size_t factor = 1; char *p; - n = strtoul(text, &p, 0); - size = n; + size = strtoul(text, &p, 0); + if (size == ULONG_MAX && errno == ERANGE) { + parse_error(_("invalid size: numeric overflow occurred")); + return 2; + } + switch (*p) { case 't': case 'T': - size *= 1024; + factor = 1024; case 'g': case 'G': - size *= 1024; + factor *= 1024; case 'm': case 'M': - size *= 1024; + factor *= 1024; case 'k': case 'K': - size *= 1024; + factor *= 1024; p++; if (*p && (*p == 'b' || *p == 'B')) p++; break; case 0: + factor = 1; break; default: @@ -3329,12 +3335,12 @@ strtosize(const char *text, size_t *psize) return 1; } - if (size < n) { + if (((size_t)-1) / factor < size) { parse_error(_("invalid size: numeric overflow occurred")); return 2; } - *psize = size; + *psize = size * factor; return 0; } @@ -3359,7 +3365,8 @@ pragma_stacksize(int argc, char **argv, const char *text) return; } case 2: - strtosize(argv[1], &size); + if (strtosize(argv[1], &size)) + return; } stack_size = size; @@ -570,46 +570,39 @@ env_fixup_autos(eval_environ_t env, ptrdiff_t offset) int -expand_dataseg(eval_environ_t env, size_t count, const char *errtext) +expand_dataseg(eval_environ_t env, size_t count) { STKVAL *newds; ptrdiff_t offset; size_t new_stack_size; size_t diff; + enum { DATASEG_MAX = ((size_t)-1) / sizeof(STKVAL) }; switch (stack_expand_policy) { case stack_expand_add: diff = ((count + stack_expand_incr - 1) / stack_expand_incr) * stack_expand_incr; + if (DATASEG_MAX - diff < env->stack_size) + return -1; new_stack_size = env->stack_size + diff; break; case stack_expand_twice: - new_stack_size = 2 * env->stack_size; - if (new_stack_size < env->stack_size) { - if (errtext) - runtime_error(env, "%s", errtext); - else - return 1; - } - diff = new_stack_size - env->stack_size; - if (diff < count) { - if (errtext) - runtime_error(env, "%s", errtext); - else - return 1; - } + new_stack_size = env->stack_size; + do { + if (DATASEG_MAX / 2 < new_stack_size) + return -1; + new_stack_size *= 2; + diff = new_stack_size - env->stack_size; + } while (diff < count); } if ((stack_max_size && new_stack_size > stack_max_size) + || DATASEG_MAX - datasize < new_stack_size || (newds = realloc(env->dataseg, (new_stack_size + datasize) - * sizeof env->dataseg[0])) == NULL) { - if (errtext) - runtime_error(env, "%s", errtext); - else - return 1; - } + * sizeof env->dataseg[0])) == NULL) + return 1; offset = (char*)newds - (char*)env->dataseg; env->dataseg = newds; @@ -772,8 +765,9 @@ push(eval_environ_t env, STKVAL val) ("tos=%lu, toh=%lu", (unsigned long) env->tos, (unsigned long) env->toh)); - expand_dataseg(env, 1, - _("out of stack space; increase #pragma stacksize")); + if (expand_dataseg(env, 1)) + runtime_error(env, "%s", + _("out of stack space; increase #pragma stacksize")); } env->dataseg[env->tos--] = val; } @@ -790,9 +784,11 @@ size_t heap_reserve_words(eval_environ_t env, size_t words) { size_t off = env->toh; - if (env->toh + words > env->tos) - expand_dataseg(env, words, - _("heap overrun; increase #pragma stacksize")); + if (env->toh + words > env->tos) { + if (expand_dataseg(env, words)) + runtime_error(env, "%s", + _("heap overrun; increase #pragma stacksize")); + } env->toh += words; return off; } @@ -808,9 +804,11 @@ heap_tempspace(eval_environ_t env, size_t size) { size_t words = B2STACK(size); STKVAL ret; - if (env->toh + words > env->tos) - expand_dataseg(env, words, - _("heap overrun; increase #pragma stacksize")); + if (env->toh + words > env->tos) { + if (expand_dataseg(env, words)) + runtime_error(env, "%s", + _("heap overrun; increase #pragma stacksize")); + } mf_c_val(ret, ptr) = env->dataseg + env->toh; return ret; } @@ -847,9 +845,11 @@ heap_obstack_grow(eval_environ_t env, void * MFL_DATASEG ptr, size_t size) char *ret; env_register_auto(env, (void*) &ptr); - if (env->tos - env->toh < words + B2STACK(env->temp_size)) - expand_dataseg(env, words, - _("memory chunk too big to fit into heap")); + if (env->tos - env->toh < words + B2STACK(env->temp_size)) { + if (expand_dataseg(env, words)) + runtime_error(env, "%s", + _("memory chunk too big to fit into heap")); + } ret = (char*) env_data_ref(env, env->temp_start) + env->temp_size; if (ptr) memmove(ret, ptr, size); @@ -1037,8 +1037,9 @@ instr_stkalloc(eval_environ_t env) (unsigned long) env->tos, (unsigned long) env->toh, n)); - expand_dataseg(env, env->toh - (env->tos - n), - _("Out of stack space; increase #pragma stacksize")); + if (expand_dataseg(env, env->toh - (env->tos - n))) + runtime_error(env, "%s", + _("Out of stack space; increase #pragma stacksize")); } env->tos -= n; advance_pc(env, 1); @@ -2416,7 +2417,7 @@ env_vsprintf(eval_environ_t env, const char *biname, size_t size; if (env->tos == env->toh) - if (expand_dataseg(env, B2STACK(strlen(fmt)), NULL)) { + if (expand_dataseg(env, B2STACK(strlen(fmt)))) { env_vsprintf_error(fmt, ap); break; } @@ -2428,8 +2429,8 @@ env_vsprintf(eval_environ_t env, const char *biname, if (biname) { n = snprintf(s, size, "%s: ", biname); if (n >= size) { - n += strlen(fmt); /* rough estimation */ - if (expand_dataseg(env, B2STACK(n), NULL)) { + n += strlen(fmt); /* rough estimate */ + if (expand_dataseg(env, B2STACK(n))) { env_vsprintf_error(fmt, ap); break; } @@ -2438,7 +2439,7 @@ env_vsprintf(eval_environ_t env, const char *biname, } k = vsnprintf(s + n, size - n, fmt, ap); if (k >= size) { - if (expand_dataseg(env, B2STACK(k), NULL)) { + if (expand_dataseg(env, B2STACK(k))) { env_vsprintf_error(fmt, ap); break; } @@ -111,7 +111,7 @@ void env_get_locus(eval_environ_t env, struct mu_locus_range *loc); STKVAL env_get_reg(eval_environ_t env); prog_counter_t env_register_read(eval_environ_t env, int what); char *env_vaptr(eval_environ_t env, size_t off); -int expand_dataseg(eval_environ_t env, size_t count, const char *errtext); +int expand_dataseg(eval_environ_t env, size_t count); void *env_get_builtin_priv(eval_environ_t env, int id); int builtin_priv_register(void *(*init)(void), void (*destroy)(void*), |