diff options
Diffstat (limited to 'src/prog.c')
-rw-r--r-- | src/prog.c | 276 |
1 files changed, 191 insertions, 85 deletions
@@ -235,6 +235,10 @@ disable_prog_trace(const char *modlist) /* Run-time evaluation */ +/* Max. number of C locals to save in struct eval_environ for eventual fixups. + See comment to env_fixup_autos, below. */ +#define MAX_AUTO_PTR 128 + struct eval_environ { prog_counter_t pc; /* Program counter */ @@ -253,6 +257,10 @@ struct eval_environ { /* Temporary heap space */ size_t temp_start; size_t temp_size; + + STKVAL *auto_ptr[MAX_AUTO_PTR]; /* Pointers to C automatic variables + referring to dataseg. */ + size_t numautos; /* Number of entries in auto_ptr. */ /* Sendmail interaction data: */ SMFICTX *ctx; /* Milter Context */ @@ -328,12 +336,52 @@ env_get_stream(eval_environ_t env) return env->stream; } + +/* A call to expand_dataseg (see below) invalidates any C variables that + pointed to dataseg before the call. To avoid dereferencing invalid memory + pointers, the addresses of such C variables are stored in env->auto_ptr + using env_register_auto (it is done by get_string_arg). When + expand_dataseg is called, it calls env_fixup_autos and passes it the + offset of new dataseg from old one. env_fixup_autos adds this value to + every address in auto_ptr, thereby fixing them. + + The auto_ptr array is cleared (by calling env_unregister_autos) after + executing each instruction (see eval_environment). + */ +void +env_register_auto(eval_environ_t env, void *ptr) +{ + if (env->numautos == MAX_AUTO_PTR) + runtime_error(env, "INTERNAL ERROR at %s:%d, please report", + __FILE__, __LINE__); + env->auto_ptr[env->numautos++] = ptr; +} + +void +env_unregister_autos(eval_environ_t env) +{ + env->numautos = 0; +} + +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]; + *pptr += offset; + } +} + + #define STACK_EXPAND_BLOCK 64 static int expand_dataseg(eval_environ_t env, size_t count, const char *errtext) { STKVAL *newds; + ptrdiff_t offset; + count = ((count + STACK_EXPAND_BLOCK - 1) / STACK_EXPAND_BLOCK) * STACK_EXPAND_BLOCK; newds = realloc(env->dataseg, @@ -346,6 +394,7 @@ expand_dataseg(eval_environ_t env, size_t count, const char *errtext) return 1; } + offset = (char*)newds - (char*)env->dataseg; env->dataseg = newds; env->stack_size += count; env->tos += count; @@ -353,6 +402,7 @@ expand_dataseg(eval_environ_t env, size_t count, const char *errtext) memmove(newds + env->tos, newds + env->tos - count, (datasize + env->stack_size - env->tos) * sizeof newds[0]); + env_fixup_autos(env, offset); mu_error(_("Warning: stack segment expanded, new size=%lu"), (unsigned long) env->stack_size); return 0; @@ -462,10 +512,11 @@ get_immediate(eval_environ_t env, unsigned n) return prog[env->pc + n + 1]; } -const char * -get_literal(eval_environ_t env, unsigned n) +void +get_literal(eval_environ_t env, unsigned n, const char **p) { - return (char*)(env->dataseg + (size_t) get_immediate(env, n)); + *p = (char*)(env->dataseg + (size_t) get_immediate(env, n)); + env_register_auto(env, p); } STKVAL @@ -474,25 +525,31 @@ get_arg(eval_environ_t env, unsigned n) return env->dataseg[env->tos + n + 1]; } -char * -get_string_arg(eval_environ_t env, unsigned n) +void +get_string_arg(eval_environ_t env, unsigned n, char **p) { - return (char*) (env->dataseg + (size_t) get_arg(env, n)); + *p = (char*) (env->dataseg + (size_t) get_arg(env, n)); + env_register_auto(env, p); } -size_t -get_numeric_arg(eval_environ_t env, unsigned n) +void +get_numeric_arg(eval_environ_t env, unsigned n, long *np) { - return (size_t) get_arg(env, n); + *np = (long) get_arg(env, n); +} + +void +get_pointer_arg(eval_environ_t env, unsigned n, void **p) +{ + *p = (void*) get_arg(env, n); } void push(eval_environ_t env, STKVAL val) { - if (env->tos < env->toh) + if (env->tos < env->toh) runtime_error(env, "INTERNAL ERROR at %s:%d, please report", __FILE__, __LINE__); - if (env->tos == env->toh) { debug2(100, "tos=%lu, toh=%lu", (unsigned long) env->tos, @@ -591,8 +648,8 @@ pushs(eval_environ_t env, char *s) void instr_locus(eval_environ_t env) { - env->locus.file = get_literal(env, 0); env->locus.line = (size_t) get_immediate(env, 1); + get_literal(env, 0, &env->locus.file); if (PROG_TRACE_ENGINE) prog_trace(env, "LOCUS"); advance_pc(env, 2); @@ -687,6 +744,14 @@ instr_stkalloc(eval_environ_t env) unsigned n = (unsigned) get_immediate(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "STKALLOC %p", n); + if (env->tos - n < env->toh) { + debug3(100, "tos=%lu, toh=%lu, delta=%u", + (unsigned long) env->tos, + (unsigned long) env->toh, + n); + expand_dataseg(env, env->toh - (env->tos - n), + _("Out of stack space; increase #pragma stacksize")); + } env->tos -= n; advance_pc(env, 1); } @@ -743,10 +808,13 @@ dump_backref(prog_counter_t i) void instr_ston(eval_environ_t env) { - char *s = get_string_arg(env, 0); + char *s; char *p; - long v = strtol(s, &p, 0); + long v; + get_string_arg(env, 0, &s); + v = strtol(s, &p, 0); + adjust_stack(env, 1); if (PROG_TRACE_ENGINE) prog_trace(env, "STON %s", s); @@ -761,7 +829,7 @@ instr_ston(eval_environ_t env) void instr_ntos(eval_environ_t env) { - long v = (long) get_numeric_arg(env, 0); + long v = (long) get_arg(env, 0); char buf[NUMERIC_BUFSIZE_BOUND]; adjust_stack(env, 1); @@ -776,8 +844,8 @@ instr_ntos(eval_environ_t env) void instr_cmp(eval_environ_t env) { - long l = (long) get_numeric_arg(env, 1); - long r = (long) get_numeric_arg(env, 0); + long l = (long) get_arg(env, 1); + long r = (long) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "CMP %ld %ld", l, r); @@ -787,8 +855,10 @@ instr_cmp(eval_environ_t env) void instr_symbol(eval_environ_t env) { - char *symbol = (char *) get_literal(env, 0); - char *s = env->getsym(env->data, symbol); + char *symbol, *s; + + get_literal(env, 0, (const char **)&symbol); + s = env->getsym(env->data, symbol); if (PROG_TRACE_ENGINE) prog_trace(env, "SYMBOL %s", symbol); @@ -815,8 +885,8 @@ dump_symbol(prog_counter_t i) void instr_eqn(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "EQN %ld %ld", a, b); adjust_stack(env, 2); @@ -826,8 +896,9 @@ instr_eqn(eval_environ_t env) void instr_eqs(eval_environ_t env) { - char *a = get_string_arg(env, 1); - char *b = get_string_arg(env, 0); + char *a, *b; + get_string_arg(env, 1, &a); + get_string_arg(env, 0, &b); if (PROG_TRACE_ENGINE) prog_trace(env, "EQS %s %s", a, b); adjust_stack(env, 2); @@ -837,8 +908,8 @@ instr_eqs(eval_environ_t env) void instr_nen(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "NEN %ld %ld", a, b); adjust_stack(env, 2); @@ -848,8 +919,10 @@ instr_nen(eval_environ_t env) void instr_nes(eval_environ_t env) { - char *a = get_string_arg(env, 1); - char *b = get_string_arg(env, 0); + char *a, *b; + + get_string_arg(env, 1, &a); + get_string_arg(env, 0, &b); if (PROG_TRACE_ENGINE) prog_trace(env, "NES %s %s", a, b); adjust_stack(env, 2); @@ -859,8 +932,8 @@ instr_nes(eval_environ_t env) void instr_ltn(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "LTN %ld %ld", a, b); adjust_stack(env, 2); @@ -870,8 +943,10 @@ instr_ltn(eval_environ_t env) void instr_lts(eval_environ_t env) { - char *a = get_string_arg(env, 1); - char *b = get_string_arg(env, 0); + char *a, *b; + + get_string_arg(env, 1, &a); + get_string_arg(env, 0, &b); if (PROG_TRACE_ENGINE) prog_trace(env, "LTS %s %s", a, b); adjust_stack(env, 2); @@ -881,8 +956,8 @@ instr_lts(eval_environ_t env) void instr_len(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "LEN %ld %ld", a, b); adjust_stack(env, 2); @@ -892,8 +967,10 @@ instr_len(eval_environ_t env) void instr_les(eval_environ_t env) { - char *a = get_string_arg(env, 1); - char *b = get_string_arg(env, 0); + char *a, *b; + + get_string_arg(env, 1, &a); + get_string_arg(env, 0, &b); if (PROG_TRACE_ENGINE) prog_trace(env, "LES %s %s", a, b); adjust_stack(env, 2); @@ -903,8 +980,8 @@ instr_les(eval_environ_t env) void instr_gtn(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "GTN %ld %ld", a, b); adjust_stack(env, 2); @@ -914,8 +991,10 @@ instr_gtn(eval_environ_t env) void instr_gts(eval_environ_t env) { - char *a = get_string_arg(env, 1); - char *b = get_string_arg(env, 0); + char *a, *b; + + get_string_arg(env, 1, &a); + get_string_arg(env, 0, &b); if (PROG_TRACE_ENGINE) prog_trace(env, "GTS %s %s", a, b); adjust_stack(env, 2); @@ -925,8 +1004,8 @@ instr_gts(eval_environ_t env) void instr_gen(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "GEN %ld %ld", a, b); adjust_stack(env, 2); @@ -936,8 +1015,10 @@ instr_gen(eval_environ_t env) void instr_ges(eval_environ_t env) { - char *a = get_string_arg(env, 1); - char *b = get_string_arg(env, 0); + char *a, *b; + + get_string_arg(env, 1, &a); + get_string_arg(env, 0, &b); if (PROG_TRACE_ENGINE) prog_trace(env, "GES %s %s", a, b); adjust_stack(env, 2); @@ -948,7 +1029,7 @@ instr_ges(eval_environ_t env) void instr_bz(eval_environ_t env) { - long v = (long) get_numeric_arg(env, 0); + long v = (long) get_arg(env, 0); long off = (long) get_immediate(env, 0); if (PROG_TRACE_ENGINE) @@ -968,7 +1049,7 @@ dump_branch (prog_counter_t i) void instr_bnz(eval_environ_t env) { - long v = (long) get_numeric_arg(env, 0); + long v = (long) get_arg(env, 0); long off = (long) get_immediate(env, 0); if (PROG_TRACE_ENGINE) @@ -992,7 +1073,7 @@ instr_jmp(eval_environ_t env) void instr_not(eval_environ_t env) { - long v = (long) get_numeric_arg(env, 0); + long v = (long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "NOT %ld", v); adjust_stack(env, 1); @@ -1003,8 +1084,8 @@ instr_not(eval_environ_t env) void instr_logand(eval_environ_t env) { - unsigned long a = (unsigned long) get_numeric_arg(env, 1); - unsigned long b = (unsigned long) get_numeric_arg(env, 0); + unsigned long a = (unsigned long) get_arg(env, 1); + unsigned long b = (unsigned long) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "LOGAND %lu %lu", a, b); @@ -1014,8 +1095,8 @@ instr_logand(eval_environ_t env) void instr_logor(eval_environ_t env) { - unsigned long a = (unsigned long) get_numeric_arg(env, 1); - unsigned long b = (unsigned long) get_numeric_arg(env, 0); + unsigned long a = (unsigned long) get_arg(env, 1); + unsigned long b = (unsigned long) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "LOGOR %lu %lu", a, b); @@ -1025,8 +1106,8 @@ instr_logor(eval_environ_t env) void instr_logxor(eval_environ_t env) { - unsigned long a = (unsigned long) get_numeric_arg(env, 1); - unsigned long b = (unsigned long) get_numeric_arg(env, 0); + unsigned long a = (unsigned long) get_arg(env, 1); + unsigned long b = (unsigned long) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "LOGXOR %lu %lu", a, b); @@ -1036,7 +1117,7 @@ instr_logxor(eval_environ_t env) void instr_lognot(eval_environ_t env) { - unsigned long v = (unsigned long) get_numeric_arg(env, 0); + unsigned long v = (unsigned long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "LOGNOT %ld", v); adjust_stack(env, 1); @@ -1047,8 +1128,8 @@ instr_lognot(eval_environ_t env) void instr_add(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "ADD %ld %ld", a, b); @@ -1058,8 +1139,8 @@ instr_add(eval_environ_t env) void instr_sub(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "SUB %ld %ld", a, b); @@ -1069,8 +1150,8 @@ instr_sub(eval_environ_t env) void instr_mul(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "MUL %ld %ld", a, b); @@ -1080,8 +1161,8 @@ instr_mul(eval_environ_t env) void instr_div(eval_environ_t env) { - long a = (long) get_numeric_arg(env, 1); - long b = (long) get_numeric_arg(env, 0); + long a = (long) get_arg(env, 1); + long b = (long) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "DIV %ld %ld", a, b); @@ -1094,7 +1175,7 @@ instr_div(eval_environ_t env) void instr_neg(eval_environ_t env) { - long v = (long) get_numeric_arg(env, 0); + long v = (long) get_arg(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "NEG %ld", v); adjust_stack(env, 1); @@ -1135,9 +1216,11 @@ void instr_regmatch(eval_environ_t env) { int v; - size_t index = (size_t)get_numeric_arg(env, 0); + size_t index = (size_t)get_arg(env, 0); regex_t *re = ®tab[index].re; - char *string = get_string_arg(env, 1); + char *string; + + get_string_arg(env, 1, &string); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) @@ -1167,9 +1250,11 @@ instr_regcomp(eval_environ_t env) int v; char buffer[REGEX_STRING_BUFSIZE]; size_t expr_off = (size_t)get_arg(env, 0); - char *expr = get_string_arg(env, 0); + char *expr; size_t index = (size_t) get_immediate(env, 0); struct rt_regex *rtx = ®tab[index]; + + get_string_arg(env, 0, &expr); advance_pc(env, 1); adjust_stack(env, 1); @@ -1211,8 +1296,10 @@ dump_regcomp(prog_counter_t i) void instr_fnmatch(eval_environ_t env) { - char *string = get_string_arg(env, 1); - char *pattern = get_string_arg(env, 0); + char *string, *pattern; + + get_string_arg(env, 1, &string); + get_string_arg(env, 0, &pattern); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "FNMATCH %s %s", string, pattern); @@ -1258,8 +1345,10 @@ fn_matcher(const char *string, void *data) void instr_fnmatch_mx(eval_environ_t env) { - char *string = get_string_arg(env, 1); - char *pattern = get_string_arg(env, 0); + char *string, *pattern; + + get_string_arg(env, 1, &string); + get_string_arg(env, 0, &pattern); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) @@ -1277,9 +1366,11 @@ void instr_regmatch_mx(eval_environ_t env) { int rc; - size_t index = (size_t)get_numeric_arg(env, 0); + size_t index = (size_t)get_arg(env, 0); regex_t *re = ®tab[index].re; - char *string = get_string_arg(env, 1); + char *string; + + get_string_arg(env, 1, &string); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) @@ -1307,9 +1398,12 @@ void instr_result(eval_environ_t env) { sfsistat status = (sfsistat) get_immediate(env, 0); - char *code = (char *) get_literal(env, 1); - char *xcode = (char *) get_literal(env, 2); - char *message = get_string_arg(env, 0); + char *code, *xcode; + char *message; + + get_string_arg(env, 0, &message); + get_literal(env, 1, (const char**)&code); + get_literal(env, 2, (const char**)&xcode); if (PROG_TRACE_ENGINE) prog_trace(env, "RESULT %d %s %s %s", @@ -1350,11 +1444,13 @@ void instr_header(eval_environ_t env) { struct old_header_node *hdr = xmalloc (sizeof(*hdr)); + char *value; hdr->opcode = (enum header_opcode) get_immediate(env, 0); - hdr->name = get_literal(env, 1); - hdr->value = strdup(get_string_arg(env, 0)); - + get_literal(env, 1, &hdr->name); + get_string_arg(env, 0, &value); + hdr->value = strdup(value); + advance_pc(env, 2); adjust_stack(env, 1); @@ -1382,9 +1478,10 @@ dump_header(prog_counter_t i) void instr_builtin(eval_environ_t env) { - const char *name = get_literal(env, 0); + const char *name; void (*handler)(eval_environ_t) = get_immediate(env, 1); + get_literal(env, 0, &name); if (PROG_TRACE_ENGINE) prog_trace(env, "BUILTIN %s", name); advance_pc(env, 2); @@ -1400,10 +1497,14 @@ dump_builtin(prog_counter_t i) void instr_concat(eval_environ_t env) { - char *left = get_string_arg(env, 1); - char *right = get_string_arg(env, 0); - size_t off = heap_reserve(env, strlen(left) + strlen(right) + 1); - char *res = (char*) env_data_ref(env, off); + char *left, *right; + size_t off; + char *res; + + get_string_arg(env, 1, &left); + get_string_arg(env, 0, &right); + off = heap_reserve(env, strlen(left) + strlen(right) + 1); + res = (char*) env_data_ref(env, off); strcat(strcpy(res, left), right); adjust_stack(env, 2); @@ -1422,7 +1523,7 @@ void instr_asgn(eval_environ_t env) { STKVAL val = get_arg(env, 1); - size_t dest = get_numeric_arg(env, 0); + size_t dest = (size_t) get_arg(env, 0); adjust_stack(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "ASGN %lu=%lu", @@ -1576,8 +1677,9 @@ instr_pushreg(eval_environ_t env) void instr_funcall(eval_environ_t env) { - const char *name = get_literal(env, 0); + const char *name; prog_counter_t pc = (prog_counter_t) get_immediate(env, 1); + get_literal(env, 0, &name); advance_pc(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "FUNCALL %s (%lu)", name, (unsigned long)pc); @@ -1760,6 +1862,8 @@ env_init(eval_environ_t env) env->matchcount = 0; env->string = NULL; + env->numautos = 0; + /* Initialize catch functions */ memcpy (env->catch, env->defcatch, sizeof env->catch); @@ -1806,8 +1910,10 @@ eval_environment(eval_environ_t env, prog_counter_t start) runtime_error(env, _("pc out of range")); if (!prog[env->pc]) break; - if (setjmp(env->catch_jmp) == 0) + if (setjmp(env->catch_jmp) == 0) { (*(prog[env->pc]))(env); + env_unregister_autos(env); + } } return 0; } |