summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-01-29 18:09:35 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-01-29 18:09:35 (GMT)
commit71c8a9513b43e30358a3c5f0448a768d908852f2 (patch) (side-by-side diff)
treeca723fbefd708e691d55567f593075ac0d9ed62c
parent84800d74f3c2855fe80d1bc5060923cdb9046551 (diff)
downloadmailfromd-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 (more/less context) (show whitespace changes)
-rw-r--r--src/builtin/sprintf.bi96
-rw-r--r--src/prog.c19
2 files changed, 62 insertions, 53 deletions
diff --git a/src/builtin/sprintf.bi b/src/builtin/sprintf.bi
index 11effd5..0a927dd 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;
}
}
diff --git a/src/prog.c b/src/prog.c
index 83401ef..75b5228 100644
--- a/src/prog.c
+++ b/src/prog.c
@@ -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,31 +493,38 @@ 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];
+ 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);

Return to:

Send suggestions and report system problems to the System administrator.