diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-03-24 22:36:19 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-03-25 01:53:22 +0200 |
commit | 1a21d080117d2e3468e0056d5972abba4d48b0b9 (patch) | |
tree | e563f8e9fe695f4e9229fb30d3f6bca2250b4432 | |
parent | 05b53f9efe69acfd21454d3d34d6d7e41d9f885f (diff) | |
download | mailfromd-1a21d080117d2e3468e0056d5972abba4d48b0b9.tar.gz mailfromd-1a21d080117d2e3468e0056d5972abba4d48b0b9.tar.bz2 |
Fix dataseg expansion (see d91911e8).
* mfd/prog.c (eval_environ) <string>: Remove. The pointer is
invalidated after dataseg expansion. Keep offset of the
last matched string in matchstr instead (data offset is
invariant). All callers updated.
(expand_dataseg): Remove static qualifier.
(instr_memstk, instr_xmemstk): Bugfix. Both functions were not
expansion-safe.
* mfd/prog.h (expand_dataseg): New proto.
-rw-r--r-- | mfd/prog.c | 44 | ||||
-rw-r--r-- | mfd/prog.h | 1 |
2 files changed, 34 insertions, 11 deletions
@@ -269,7 +269,8 @@ struct eval_environ { regmatch_t *matches; /* Match map */ size_t matchcount; /* Number of used entries in matches */ size_t matchsize; /* Total number of entries in matches */ - char *string; /* Last matched string */ + prog_counter_t matchstr; /* Pointer to the last matched string + in the dataseg. */ mu_stream_t stream; /* Capture stream */ size_t line_count; /* Number of lines in stream */ @@ -396,7 +397,7 @@ env_fixup_autos(eval_environ_t env, ptrdiff_t offset) } -static int +int expand_dataseg(eval_environ_t env, size_t count, const char *errtext) { STKVAL *newds; @@ -769,14 +770,29 @@ instr_memstk(eval_environ_t env) { size_t frame = (size_t) get_immediate(env, 0); long off = (long) get_immediate(env, 1); - size_t val = env_base(env, frame) + off; + size_t val; + + /* The naive approach would be to just + push(env, env_base(env, frame) + off) + + However, push() itself might cause dataseg expansion, + which would change tos/toh pointers and render the previously + computed argument value invalid. The correct way is to push + a placeholder value first, thereby occupying stack slot and + eventually causing dataseg expansion, and then compute val + using actual environment: + */ + + push(env, 0); + val = env_base(env, frame) + off; + env->dataseg[env->tos+1] = (STKVAL)val; + if (PROG_TRACE_ENGINE) prog_trace(env, "MEMSTK %lu(%ld)=%lu", (unsigned long) frame, off, (unsigned long) val); advance_pc(env, 2); - push(env, (STKVAL) val); } void @@ -790,14 +806,18 @@ instr_xmemstk(eval_environ_t env) { size_t frame = (size_t) get_arg(env, 1); long off = (long) get_arg(env, 0); - size_t val = env_base(env, frame) + off; + size_t val; + + /* See comment in instr_memstk, above */ + push(env, 0); + val = env_base(env, frame) + off; + env->dataseg[env->tos+1] = (STKVAL)val; if (PROG_TRACE_ENGINE) prog_trace(env, "XMEMSTK %lu(%ld)=%lu", (unsigned long) frame, off, (unsigned long) val); adjust_stack(env, 2); - push(env, (STKVAL) val); } void @@ -848,7 +868,7 @@ instr_backref(eval_environ_t env) prog_trace(env, "BACKREF %u", (unsigned)get_immediate(env, 0)); advance_pc(env, 1); - if (!env->matches || !env->string) { + if (!env->matches || !env->matchstr) { /* FIXME: Try to throw exception first: env_throw(env, mf_no_regex); */ @@ -864,11 +884,12 @@ instr_backref(eval_environ_t env) } else { char *s; size_t off; - + const char *str = (const char *) &env->dataseg[env->matchstr]; + matchlen = env->matches[n].rm_eo - env->matches[n].rm_so; off = heap_reserve(env, matchlen + 1); s = (char*) env_data_ref(env, off); - memcpy(s, env->string + env->matches[n].rm_so, matchlen); + memcpy(s, str + env->matches[n].rm_so, matchlen); s[matchlen] = 0; push(env, (STKVAL) off); } @@ -1300,6 +1321,8 @@ instr_regmatch(eval_environ_t env) char *string; get_string_arg(env, 1, &string); + env->matchstr = (STKVAL*)string - env->dataseg; + adjust_stack(env, 2); if (PROG_TRACE_ENGINE) @@ -1318,7 +1341,6 @@ instr_regmatch(eval_environ_t env) } v = regexec(re, string, env->matchcount + 1, env->matches, 0); - env->string = string; push(env, (STKVAL) (v == 0)); } @@ -1983,7 +2005,7 @@ env_init(eval_environ_t env) env->matches = NULL; env->matchsize = 0; env->matchcount = 0; - env->string = NULL; + env->matchstr = 0; env->numautos = 0; @@ -55,6 +55,7 @@ void env_var_inc(eval_environ_t env, size_t off); const struct locus *env_get_locus(eval_environ_t env); STKVAL env_get_reg(eval_environ_t env); char *env_vaptr(eval_environ_t env, size_t off); +int expand_dataseg(eval_environ_t env, size_t count, const char *errtext); void *env_get_builtin_priv(eval_environ_t env, int id); int builtin_priv_register(void *(*init)(void), void (*destroy)(void*), |