diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-01-29 20:09:35 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-01-29 20:09:35 +0200 |
commit | 71c8a9513b43e30358a3c5f0448a768d908852f2 (patch) | |
tree | ca723fbefd708e691d55567f593075ac0d9ed62c /src | |
parent | 84800d74f3c2855fe80d1bc5060923cdb9046551 (diff) | |
download | mailfromd-71c8a9513b43e30358a3c5f0448a768d908852f2.tar.gz mailfromd-71c8a9513b43e30358a3c5f0448a768d908852f2.tar.bz2 |
Fixes in runtime memory management
* src/builtin/sprintf.bi: Don't use pointer to format: the latter
might be reallocated during stack expansions, and the pointer would
end up pointing to freed memory area. Another way to fix it would be
to make env_register_auto and env_pop_auto global and to mark the
address of pointer with env_register_auto so it would be reallocated
together with format. However, I wouldn't like to expose too much of
the internals of prog.c.
* src/prog.c (env_get_locus)
(heap_obstack_grow,pushs): Fix argument to env_register_auto.
(env_register_auto): Check if the argument points to a memory
location within data segment + stack. This is necessary, because
heap_obstack_grow registers its argument, which at least in one case
is a pointer to an automatic variable (see MF_OBSTACK_1GROW in
builtin/snarf.m4).
(env_pop_auto,env_unregister_autos)
(env_fixup_autos): Make static.
Diffstat (limited to 'src')
-rw-r--r-- | src/builtin/sprintf.bi | 96 | ||||
-rw-r--r-- | src/prog.c | 21 |
2 files changed, 63 insertions, 54 deletions
diff --git a/src/builtin/sprintf.bi b/src/builtin/sprintf.bi index 11effd58..0a927dd2 100644 --- a/src/builtin/sprintf.bi +++ b/src/builtin/sprintf.bi @@ -34,14 +34,15 @@ typedef enum { fmts_conv /* Expect conversion specifier */ } printf_format_state; -char * -get_num(char *p, unsigned *pn) +static int +get_num(const char *p, int i, unsigned *pn) { unsigned n = 0; - for (; *p && mu_isdigit(*p); p++) - n = n * 10 + *p - '0'; + + for (; p[i] && mu_isdigit(p[i]); i++) + n = n * 10 + p[i] - '0'; *pn = n; - return p; + return i; } #define __MF_MAX(a,b) ((a)>(b) ? (a) : (b)) @@ -50,8 +51,8 @@ get_num(char *p, unsigned *pn) MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) { int i = 0; - char *p = format; - char *start; + int cur = 0; + int start; char buf[SPRINTF_BUF_SIZE]; printf_format_state state = fmts_copy; int flags = 0; @@ -61,7 +62,7 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) MF_OBSTACK_BEGIN(); MF_VA_START(); - while (*p) { + while (format[cur]) { unsigned n; char *str; long num; @@ -71,31 +72,31 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) switch (state) { case fmts_copy: /* Expect `%', and copy all the rest verbatim */ - if (*p == '%') { - start = p; + if (format[cur] == '%') { + start = cur; state = fmts_pos; flags = 0; width = 0; prec = 0; } else - MF_OBSTACK_1GROW(*p); - p++; + MF_OBSTACK_1GROW(format[cur]); + cur++; break; case fmts_pos: /* Expect '%' or an argument position -- %_% or %_2$ */ - if (*p == '%') { + if (format[cur] == '%') { MF_OBSTACK_1GROW('%'); - p++; + cur++; state = fmts_copy; break; } - if (mu_isdigit(*p)) { - char *q = get_num(p, &n); - if (*q == '$') { + if (mu_isdigit(format[cur])) { + int pos = get_num(format, cur, &n); + if (format[pos] == '$') { argnum = n - 1; flags |= FMT_ALTPOS; - p = q + 1; + cur = pos + 1; } } state = fmts_flags; @@ -103,30 +104,30 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) case fmts_flags: /* Expect flags -- %2$_# */ - switch (*p) { + switch (format[cur]) { case '#': flags |= FMT_ALTERNATE; - p++; + cur++; break; case '0': flags |= FMT_PADZERO; - p++; + cur++; break; case '-': flags |= FMT_ADJUST_LEFT; - p++; + cur++; break; case ' ': flags |= FMT_SPACEPFX; - p++; + cur++; break; case '+': flags |= FMT_SIGNPFX; - p++; + cur++; break; default: @@ -136,11 +137,11 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) case fmts_width: /* Expect width -- %2$#_8 or %2$#_* */ - if (mu_isdigit(*p)) { - p = get_num(p, &width); + if (mu_isdigit(format[cur])) { + cur = get_num(format, cur, &width); state = fmts_prec; - } else if (*p == '*') { - p++; + } else if (format[cur] == '*') { + cur++; state = fmts_width_arg; } else state = fmts_prec; @@ -149,11 +150,11 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) case fmts_width_arg: /* Expect width argument position -- %2$#*_1$ */ state = fmts_prec; - if (mu_isdigit(*p)) { - char *q = get_num(p, &n); - if (*q == '$') { + if (mu_isdigit(format[cur])) { + int pos = get_num(format, cur, &n); + if (format[pos] == '$') { MF_VA_ARG(n-1, NUMBER, num); - p = q + 1; + cur = pos + 1; if (num < 0) { flags |= FMT_SPACEPFX; num = - num; @@ -176,12 +177,12 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) case fmts_prec: /* Expect precision -- %2$#*1$_. */ state = fmts_conv; - if (*p == '.') { - p++; - if (mu_isdigit(*p)) { - p = get_num(p, &prec); - } else if (*p == '*') { - p++; + if (format[cur] == '.') { + cur++; + if (mu_isdigit(format[cur])) { + cur = get_num(format, cur, &prec); + } else if (format[cur] == '*') { + cur++; state = fmts_prec_arg; } } @@ -191,13 +192,13 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) /* Expect precision argument position -- %2$#*1$.*_3$ */ state = fmts_conv; - if (mu_isdigit(*p)) { - char *q = get_num(p, &n); - if (*q == '$') { + if (mu_isdigit(format[cur])) { + int pos = get_num(format, cur, &n); + if (format[pos] == '$') { MF_VA_ARG(n-1, NUMBER, num); if (num > 0) prec = (unsigned) num; - p = q + 1; + cur = pos + 1; break; } } @@ -210,7 +211,7 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) case fmts_conv: /* Expect conversion specifier */ if (!(flags & FMT_ALTPOS)) argnum = i++; - switch (*p) { + switch (format[cur]) { case 's': MF_VA_ARG(argnum, STRING, str); n = strlen(str); @@ -331,7 +332,7 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) /* A - overrides a 0 if both are given.*/ if (prec || (flags & FMT_ADJUST_LEFT)) flags &= ~FMT_PADZERO; - fmtbuf[1] = *p; + fmtbuf[1] = format[cur]; snprintf(buf+2, sizeof(buf)-2, fmtbuf, num); str = buf + 2; n = strlen(str); @@ -342,7 +343,7 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) } if (flags & FMT_ALTERNATE) { - *--str = *p; + *--str = format[cur]; *--str = '0'; n += 2; } @@ -406,10 +407,11 @@ MF_DEFUN_VARARGS_NO_PROM(sprintf, STRING, STRING format) break; default: - MF_OBSTACK_GROW(start, p - start + 1); + MF_OBSTACK_GROW(&format[start], + cur - start + 1); } - p++; + cur++; state = fmts_copy; } } @@ -384,7 +384,7 @@ env_get_locus(eval_environ_t env, struct mu_locus_range *locus) { mu_locus_range_init(locus); locus->beg.mu_file = (char*)(env->dataseg + env->locus.file); - env_register_auto(env, (void*) locus->beg.mu_file); + env_register_auto(env, (void*) &locus->beg.mu_file); locus->beg.mu_line = env->locus.line; #if 0 locus->beg.mu_col = env->locus.point; @@ -493,32 +493,39 @@ env_function_cleanup_add(eval_environ_t env, void *data, static void env_register_auto(eval_environ_t env, void *ptr) { + char *addr = *(char**)ptr; + if (env->numautos == MAX_AUTO_PTR) runtime_error(env, "INTERNAL ERROR at %s:%d, please report", __FILE__, __LINE__); + /* Check if address is within the dataseg */ + if (!(addr >= (char*) env->dataseg + && (addr < (char*) (env->dataseg + datasize + env->stack_size)))) + ptr = NULL; env->auto_ptr[env->numautos++] = ptr; } /* Pop the last registered auto variable */ -void +static void env_pop_auto(eval_environ_t env) { env->numautos--; } -void +static void env_unregister_autos(eval_environ_t env) { env->numautos = 0; } -void +static void env_fixup_autos(eval_environ_t env, ptrdiff_t offset) { int i; for (i = 0; i < env->numautos; i++) { STKVAL *pptr = env->auto_ptr[i]; - mf_c_val(*pptr,str) += offset; /*FIXME*/ + if (pptr) + mf_c_val(*pptr,str) += offset; /*FIXME*/ } } @@ -799,7 +806,7 @@ heap_obstack_grow(eval_environ_t env, void * MFL_DATASEG ptr, size_t size) size_t words = B2STACK(size); char *ret; - env_register_auto(env, ptr); + 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")); @@ -829,7 +836,7 @@ pushs(eval_environ_t env, const char * MFL_DATASEG s) { size_t off; - env_register_auto(env, (void*) s); + env_register_auto(env, (void*) &s); off = heap_reserve(env, strlen(s) + 1); strcpy((char*) env_data_ref(env, off), s); env_pop_auto(env); |