diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | awk.h | 12 | ||||
-rw-r--r-- | awkgram.c | 2 | ||||
-rw-r--r-- | awkgram.y | 2 | ||||
-rw-r--r-- | cmd.h | 1 | ||||
-rw-r--r-- | command.c | 2 | ||||
-rw-r--r-- | command.y | 2 | ||||
-rw-r--r-- | debug.c | 55 | ||||
-rw-r--r-- | eval.c | 211 |
9 files changed, 179 insertions, 127 deletions
@@ -1,3 +1,22 @@ +Sun Nov 21 14:23:58 2010 John Haque <j.eh@mchsi.com> + + Debugger: Fix memory leak when quitting pager. + * awk.h (PUSH_BINDING, POP_BINDING): Generalize macro definitions. + * debug.c (print_array): save and restore bindings for pager. + free list in case of an early exit in the pager. + (do_dump_instructions): Don't sort functions to avoid potential + memory leak. + (execute_code): Adjust PUSH_BINDING and POP_BINDING macro invocations. + + * awkgram.y (func_call): Avoid reading freed memory for indirect var + name; do the special variable check before the call to 'variable'. + + * eval.c (r_interpret): Fixes and cleanups. Change TOP to TOP_SCALAR + in the case Op_store_field. + (assign_common, assign, compare): Nuked macros. + (cmp_scalar, op_assign): New functions as replacements for the macros. + + Fri Nov 19 11:57:28 2010 Arnold D. Robbins <arnold@skeeve.com> * bootstrap.sh, Makefile.am: Remove treatment of CVS. @@ -1081,12 +1081,12 @@ extern STACK_ITEM *stack_top; extern jmp_buf fatal_tag; extern int fatal_tag_valid; -#define PUSH_BINDING(stack) \ -if (fatal_tag_valid++) \ - memcpy((char *) (stack), (const char *) fatal_tag, sizeof(jmp_buf)) -#define POP_BINDING(stack) \ -if (--fatal_tag_valid) \ - memcpy((char *) fatal_tag, (const char *) (stack), sizeof(jmp_buf)) +#define PUSH_BINDING(stack, tag, val) \ +if (val++) \ + memcpy((char *) (stack), (const char *) tag, sizeof(jmp_buf)) +#define POP_BINDING(stack, tag, val) \ +if (--val) \ + memcpy((char *) tag, (const char *) (stack), sizeof(jmp_buf)) /* ------------- Function prototypes or defs (as appropriate) ------------- */ typedef int (*Func_print)(FILE *, const char *, ...); @@ -3955,9 +3955,9 @@ yyreduce: f = (yyvsp[(2) - (2)])->lasti; f->opcode = Op_indirect_func_call; name = estrdup(f->func_name, strlen(f->func_name)); - indirect_var = variable(name, Node_var_new); if (is_std_var(name)) yyerror(_("can not use special variable `%s' for indirect function call"), name); + indirect_var = variable(name, Node_var_new); t = instruction(Op_push); t->memory = indirect_var; @@ -1600,9 +1600,9 @@ func_call f = $2->lasti; f->opcode = Op_indirect_func_call; name = estrdup(f->func_name, strlen(f->func_name)); - indirect_var = variable(name, Node_var_new); if (is_std_var(name)) yyerror(_("can not use special variable `%s' for indirect function call"), name); + indirect_var = variable(name, Node_var_new); t = instruction(Op_push); t->memory = indirect_var; @@ -37,6 +37,7 @@ extern char **get_parmlist(void); extern int gprintf(FILE *fp, const char *format, ...); extern jmp_buf pager_quit_tag; +extern int pager_quit_tag_valid; extern int output_is_tty; extern int input_fd; @@ -2322,7 +2322,7 @@ yyreduce: for (a = (yyvsp[(2) - (3)]); a != NULL; a = a->next) count++; - subs =concat_args((yyvsp[(2) - (3)]), count); + subs = concat_args((yyvsp[(2) - (3)]), count); free_cmdarg((yyvsp[(2) - (3)])->next); (yyvsp[(2) - (3)])->next = NULL; (yyvsp[(2) - (3)])->type = D_node; @@ -632,7 +632,7 @@ subscript for (a = $2; a != NULL; a = a->next) count++; - subs =concat_args($2, count); + subs = concat_args($2, count); free_cmdarg($2->next); $2->next = NULL; $2->type = D_node; @@ -262,6 +262,7 @@ static void save_options(const char *file); /* pager */ jmp_buf pager_quit_tag; +int pager_quit_tag_valid; static int screen_width = INT_MAX; /* no of columns */ static int screen_height = INT_MAX; /* no of rows */ static int pager_lines_printed = 0; /* no of lines printed so far */ @@ -1055,7 +1056,7 @@ extern int comp_func(const void *p1, const void *p2); /* print_array --- print the contents of an array */ -static void +static int print_array(NODE *arr, char *arr_name, Func_print print_func) { NODE *bucket; @@ -1065,7 +1066,7 @@ print_array(NODE *arr, char *arr_name, Func_print print_func) if (arr->var_array == NULL || arr->table_size == 0) { print_func(out_fp, _("array `%s' is empty\n"), arr_name); - return; + return 0; } /* sort indices */ @@ -1088,13 +1089,27 @@ print_array(NODE *arr, char *arr_name, Func_print print_func) bucket = list[i]; if (bucket->ahvalue->type == Node_var_array) { arr = bucket->ahvalue; - print_array(arr, arr->vname, print_func); + if (pager_quit_tag_valid) { /* we are using pager */ + volatile jmp_buf pager_quit_tag_stack; + volatile int ret = 1; + + PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid); + if (setjmp(pager_quit_tag) == 0) + ret = print_array(arr, arr->vname, print_func); + POP_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid); + if (ret == 1) { + efree(list); + return 1; + } + } else + (void) print_array(arr, arr->vname, print_func); } else { print_func(out_fp, "%s[\"%s\"] = ", arr_name, bucket->ahname_str); valinfo(bucket->ahvalue, print_func, out_fp); } } efree(list); + return 0; } /* print_subscript --- print an array element */ @@ -1173,8 +1188,10 @@ do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) } if (count == 0) { initialize_pager(out_fp); + pager_quit_tag_valid = TRUE; if (setjmp(pager_quit_tag) == 0) print_array(r, name, gprintf); + pager_quit_tag_valid = FALSE; } } break; @@ -1624,17 +1641,17 @@ static int cmp_val(struct list_item *w, NODE *old, NODE *new) { /* - * case old new result + * case old new result * ------------------------------ - * 1: NULL ARRAY TRUE - * 2: NULL SCALAR TRUE - * 3: NULL NULL FALSE - * 4: SCALAR SCALAR cmp_node - * 5: SCALAR ARRAY TRUE - * 6: SCALAR NULL TRUE - * 7: ARRAY SCALAR TRUE - * 8: ARRAY ARRAY compare size - * 9: ARRAY NULL TRUE + * 1: NULL ARRAY TRUE + * 2: NULL SCALAR TRUE + * 3: NULL NULL FALSE + * 4: SCALAR SCALAR cmp_node + * 5: SCALAR ARRAY TRUE + * 6: SCALAR NULL TRUE + * 7: ARRAY SCALAR TRUE + * 8: ARRAY ARRAY compare size + * 9: ARRAY NULL TRUE */ if (WATCHING_ARRAY(w)) { @@ -3522,8 +3539,6 @@ post_execute(INSTRUCTION *pc, int inloop) && stop.print_ret ) { NODE *r; - - assert(stack_empty() == FALSE); /* print the returned value before it disappears. */ r = TOP(); fprintf(out_fp, "Returned value = "); @@ -3986,7 +4001,7 @@ do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) pf_data.defn = TRUE; /* in_dump = TRUE */ (void) print_code(code_block, &pf_data); (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code, - TRUE, /* sort */ + FALSE, /* sort */ &pf_data /* data */ ); fclose(fp); @@ -4000,7 +4015,7 @@ do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) pf_data.defn = TRUE; /* in_dump = TRUE */ (void) print_code(code_block, &pf_data); (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code, - TRUE, /* sort */ + FALSE, /* sort */ &pf_data /* data */ ); } @@ -4497,7 +4512,7 @@ unserialize_list_item(struct list_item *list, char **pstr, int *pstr_len, int fi int num, type, i; struct list_item *l; NODE *symbol = NULL; - int sub_cnt, cnt; + int sub_cnt = 0, cnt; NODE **subs = NULL; /* subscript -- number type sname num_subs subs [commands [condition]] @@ -5376,7 +5391,7 @@ execute_code(volatile INSTRUCTION *code) */ ctxt_stack_bottom = stack_ptr + 1; - PUSH_BINDING(fatal_tag_stack); + PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid); if (setjmp(fatal_tag) == 0) { (void) r_interpret((INSTRUCTION *) code); assert(stack_ptr == ctxt_stack_bottom); @@ -5384,7 +5399,7 @@ execute_code(volatile INSTRUCTION *code) } else /* fatal error */ unwind_stack(ctxt_stack_bottom); - POP_BINDING(fatal_tag_stack); + POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid); if (exit_val != EXIT_SUCCESS) { /* must be EXIT_FATAL? */ exit_val = EXIT_SUCCESS; @@ -1390,6 +1390,96 @@ eval_condition(NODE *t) return (t->stlen != 0); } +/* cmp_scalar -- compare two nodes on the stack */ + +static inline int +cmp_scalar() +{ + NODE *t1, *t2; + int di; + + t2 = POP_SCALAR(); + t1 = TOP(); + if (t1->type == Node_var_array) { + DEREF(t2); + fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t1)); + } + di = cmp_nodes(t1, t2); + DEREF(t1); + DEREF(t2); + return di; +} + +/* op_assign --- assignment operators excluding = */ + +static void +op_assign(OPCODE op) +{ + NODE **lhs; + NODE *r; + AWKNUM x, x1, x2; +#ifdef _CRAY + long lx; +#endif + + lhs = POP_ADDRESS(); + x1 = force_number(*lhs); + TOP_NUMBER(x2); + unref(*lhs); + switch (op) { + case Op_assign_plus: + r = *lhs = make_number(x1 + x2); + break; + case Op_assign_minus: + r = *lhs = make_number(x1 - x2); + break; + case Op_assign_times: + r = *lhs = make_number(x1 * x2); + break; + case Op_assign_quotient: + if (x2 == (AWKNUM) 0) { + decr_sp(); + fatal(_("division by zero attempted in `/='")); + } +#ifdef _CRAY + /* special case for integer division, put in for Cray */ + lx = x2; + if (lx == 0) { + r = *lhs = make_number(x1 / x2); + break; + } + lx = (long) x1 / lx; + if (lx * x1 == x2) + r = *lhs = make_number((AWKNUM) lx); + else +#endif /* _CRAY */ + r = *lhs = make_number(x1 / x2); + break; + case Op_assign_mod: + if (x2 == (AWKNUM) 0) { + decr_sp(); + fatal(_("division by zero attempted in `%%='")); + } +#ifdef HAVE_FMOD + r = *lhs = make_number(fmod(x1, x2)); +#else /* ! HAVE_FMOD */ + (void) modf(x1 / x2, &x); + x = x1 - x2 * x; + r = *lhs = make_number(x); +#endif /* ! HAVE_FMOD */ + break; + case Op_assign_exp: + r = *lhs = make_number((AWKNUM) calc_exp((double) x1, (double) x2)); + break; + default: + break; + } + + UPREF(r); + REPLACE(r); +} + + /* PUSH_CODE --- push a code onto the runtime stack */ void @@ -1748,40 +1838,34 @@ top: break; case Op_equal: - -/* compare two nodes on the stack */ -#define compare(X, Y) \ -t2 = POP_SCALAR(); \ -t1 = TOP_SCALAR(); \ -X = cmp_nodes(t1, t2); \ -DEREF(t1); \ -DEREF(t2); \ -r = make_number((AWKNUM) (Y)); \ -REPLACE(r); - - compare(di, di == 0); + r = make_number((AWKNUM) (cmp_scalar() == 0)); + REPLACE(r); break; case Op_notequal: - compare(di, di != 0); + r = make_number((AWKNUM) (cmp_scalar() != 0)); + REPLACE(r); break; case Op_less: - compare(di, di < 0); + r = make_number((AWKNUM) (cmp_scalar() < 0)); + REPLACE(r); break; case Op_greater: - compare(di, di > 0); + r = make_number((AWKNUM) (cmp_scalar() > 0)); + REPLACE(r); break; case Op_leq: - compare(di, di <= 0); + r = make_number((AWKNUM) (cmp_scalar() <= 0)); + REPLACE(r); break; case Op_geq: - compare(di, di >= 0); + r = make_number((AWKNUM) (cmp_scalar() >= 0)); + REPLACE(r); break; -#undef compare case Op_plus_i: x2 = force_number(pc->memory); @@ -1839,11 +1923,10 @@ exponent: case Op_quotient: POP_NUMBER(x2); quotient: - TOP_NUMBER(x1); - if (x2 == 0) { - decr_sp(); + if (x2 == 0) fatal(_("division by zero attempted")); - } + + TOP_NUMBER(x1); #ifdef _CRAY /* special case for integer division, put in for Cray */ lx2 = x2; @@ -1870,12 +1953,10 @@ quotient: case Op_mod: POP_NUMBER(x2); mod: - TOP_NUMBER(x1); - - if (x2 == 0) { - decr_sp(); + if (x2 == 0) fatal(_("division by zero attempted in `%%'")); - } + + TOP_NUMBER(x1); #ifdef HAVE_FMOD x = fmod(x1, x2); #else /* ! HAVE_FMOD */ @@ -1949,7 +2030,7 @@ post: */ Func_ptr assign; - t1 = TOP(); + t1 = TOP_SCALAR(); lhs = r_get_field(t1, &assign, FALSE); decr_sp(); DEREF(t1); @@ -1970,7 +2051,7 @@ post: if (t1 != t2 && t1->valref == 1 && (t1->flags & PERM) == 0) { size_t nlen = t1->stlen + t2->stlen; - erealloc(t1->stptr, char *, nlen + 2, "interpret"); + erealloc(t1->stptr, char *, nlen + 2, "r_interpret"); memcpy(t1->stptr + t1->stlen, t2->stptr, t2->stlen); t1->stlen = nlen; t1->stptr[nlen] = '\0'; @@ -1978,7 +2059,7 @@ post: size_t nlen = t1->stlen + t2->stlen; char *p; - emalloc(p, char *, nlen + 2, "interpret"); + emalloc(p, char *, nlen + 2, "r_interpret"); memcpy(p, t1->stptr, t1->stlen); memcpy(p + t1->stlen, t2->stptr, t2->stlen); unref(*lhs); @@ -1997,79 +2078,16 @@ post: REPLACE(r); break; + /* numeric assignments */ case Op_assign_plus: -#define assign_common(X, Y) \ -lhs = POP_ADDRESS(); \ -X = force_number(*lhs); \ -TOP_NUMBER(Y); \ -unref(*lhs) - -#define assign(X, Y, Z) \ -assign_common(X, Y); \ -r = *lhs = make_number(Z); \ -UPREF(r); \ -REPLACE(r) - - assign(x1, x2, x1 + x2); - break; - case Op_assign_minus: - assign(x1, x2, x1 - x2); - break; - case Op_assign_times: - assign(x1, x2, x1 * x2); - break; - case Op_assign_quotient: - assign_common(x1, x2); - if (x2 == (AWKNUM) 0) { - decr_sp(); - fatal(_("division by zero attempted in `/='")); - } -#ifdef _CRAY - /* special case for integer division, put in for Cray */ - lx = x2; - if (lx == 0) { - r = *lhs = make_number(x1 / x2); - UPREF(r); - REPLACE(r); - break; - } - lx = (long) x1 / lx; - if (lx * x1 == x2) - r = *lhs = make_number((AWKNUM) lx); - else -#endif /* _CRAY */ - r = *lhs = make_number(x1 / x2); - UPREF(r); - REPLACE(r); - break; - case Op_assign_mod: - assign_common(x1, x2); - if (x2 == (AWKNUM) 0) { - decr_sp(); - fatal(_("division by zero attempted in `%%='")); - } -#ifdef HAVE_FMOD - r = *lhs = make_number(fmod(x1, x2)); -#else /* ! HAVE_FMOD */ - (void) modf(x1 / x2, &x); - x = x1 - x2 * x; - r = *lhs = make_number(x); -#endif /* ! HAVE_FMOD */ - UPREF(r); - REPLACE(r); - break; - case Op_assign_exp: - assign(x1, x2, (AWKNUM) calc_exp((double) x1, (double) x2)); + op_assign(pc->opcode); break; -#undef assign -#undef assign_common - case Op_var_update: /* update value of NR, FNR or NF */ pc->memory->var_update(); break; @@ -2091,7 +2109,6 @@ REPLACE(r) { INSTRUCTION *curr; int match_found = FALSE; - t1 = TOP_SCALAR(); /* switch expression */ for (curr = pc->case_val; curr != NULL; curr = curr->nexti) { if (curr->opcode == Op_K_case) { @@ -2471,7 +2488,7 @@ func_call: ni = POP_CODE(); /* Op_newfile */ ni = ni->target_jmp; /* end_block or Op_atexit */ } else if (inrec(curfile) == 0) - break; /* prog block */ + break; /* prog(rule) block */ else ni = POP_CODE(); /* Op_newfile */ JUMPTO(ni); |