diff options
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | awk.h | 8 | ||||
-rw-r--r-- | awkgram.c | 110 | ||||
-rw-r--r-- | awkgram.y | 110 | ||||
-rw-r--r-- | builtin.c | 36 | ||||
-rw-r--r-- | debug.c | 20 | ||||
-rw-r--r-- | eval.c | 9 | ||||
-rw-r--r-- | main.c | 4 |
8 files changed, 185 insertions, 137 deletions
@@ -1,3 +1,28 @@ +Thu Nov 25 20:12:28 2010 John Haque <j.eh@mchsi.com> + + * awkgram.y (grammar): Bug fix in delete for loop efficiency hack. + * debug.c (do_info): Don't sort functions to avoid potential memory leak + in case A_FUNCTIONS. + + Plug more potential leaks in the debugger eval/condition commands: + * builtin.c (POP_TWO_SCALARS): New macro to free first scalar in case + of a fatal error in the next. + (do_index, do_atan2, do_lshift, do_rshift, do_and, do_or, do_xor): Use it + instead of two consecutive POP_SCALARs. + + Execution context related code cleanups. Also, added descriptive + comments for functions. + * awkgram.y (get_context): Nuked. + (push_context, pop_context, in_main_context): New functions. + (mk_program, parse_program, yylex): Updated. + * debug.c (condition_triggered, do_eval, parse_condition): Updated. + * eval.c (unwind_stack): Updated. + * main.c (main): Updated. + * awk.h (struct context): Removed member level, not needed. + + * eval.c (op_assign): Initialize r to NULL, and declare x only + if HAVE_FMOD not defined to remove GCC warnings. + Thu Nov 25 08:32:31 2010 Arnold D. Robbins <arnold@skeeve.com> * eval.c (posix_compare): Do string comparison with strcoll() / @@ -801,7 +801,7 @@ typedef struct srcfile { int lasttok; } SRCFILE; - +/* structure for execution context */ typedef struct context { INSTRUCTION pools; NODE symbols; @@ -809,7 +809,6 @@ typedef struct context { SRCFILE srcfiles; int sourceline; char *source; - int level; void (*install_func)(char *); struct context *prev; } CONTEXT; @@ -1132,8 +1131,9 @@ extern int files_are_same(struct stat *f1, struct stat *f2); extern void valinfo(NODE *n, Func_print print_func, FILE *fp); extern void print_vars(Func_print print_func, FILE *fp); extern CONTEXT *new_context(void); -extern CONTEXT *set_context(CONTEXT *ctxt); -extern CONTEXT *get_context(void); +extern void push_context(CONTEXT *ctxt); +extern void pop_context(); +extern int in_main_context(); extern void free_context(CONTEXT *ctxt, int ); extern void append_symbol(char *name); @@ -2548,7 +2548,7 @@ yyreduce: /* Line 1455 of yacc.c */ #line 599 "awkgram.y" { - + INSTRUCTION *ip; char *var_name = (yyvsp[(3) - (8)])->lextok; if ((yyvsp[(8) - (8)]) != NULL @@ -2572,8 +2572,8 @@ yyreduce: * and that both the loop var and array names match. */ NODE *arr = NULL; - INSTRUCTION *ip = (yyvsp[(8) - (8)])->nexti->nexti; + ip = (yyvsp[(8) - (8)])->nexti->nexti; if ((yyvsp[(5) - (8)])->nexti->opcode == Op_push && (yyvsp[(5) - (8)])->lasti == (yyvsp[(5) - (8)])->nexti) arr = (yyvsp[(5) - (8)])->nexti->memory; if (arr != NULL @@ -2591,7 +2591,8 @@ yyreduce: bcfree((yyvsp[(4) - (8)])); bcfree((yyvsp[(5) - (8)])); (yyval) = (yyvsp[(8) - (8)]); - } + } else + goto regular_loop; } else { /* [ Op_push_array a ] @@ -2606,8 +2607,7 @@ yyreduce: * y: [Op_pop_loop ] * w: [Op_arrayfor_final ] */ - INSTRUCTION *ip; - +regular_loop: ip = (yyvsp[(5) - (8)]); ip->nexti->opcode = Op_push_array; (yyvsp[(3) - (8)])->opcode = Op_arrayfor_init; @@ -4704,7 +4704,7 @@ mk_program() else (void) list_prepend(end_block, ip_end); - if (get_context()->level > 0) { + if (! in_main_context()) { if (begin_block != NULL && prog_block != NULL) cp = list_merge(begin_block, prog_block); else @@ -4810,7 +4810,7 @@ parse_program(INSTRUCTION **pcode) */ ip_end = instruction(Op_no_op); - if (get_context()->level > 0) + if (! in_main_context()) ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL; else { ip_endfile = instruction(Op_no_op); @@ -6054,7 +6054,7 @@ retry: want_source = TRUE; break; case LEX_EVAL: - if (get_context()->level == 0) + if (in_main_context()) goto out; emalloc(tokkey, char *, tok - tokstart + 1, "yylex"); tokkey[0] = '@'; @@ -6900,7 +6900,7 @@ check_funcs() struct fdesc *fp, *next; int i; - if (get_context()->level > 0) + if (! in_main_context()) goto free_mem; for (i = 0; i < HASHSIZE; i++) { @@ -7697,7 +7697,7 @@ optimize_assignment(INSTRUCTION *exp) /* * N.B.: do not append Op_pop instruction to the returned * instruction list if optimized. None of these - * optimized instructions push the r-value of assignment + * optimized instructions pushes the r-value of assignment * onto the runtime stack. */ @@ -8124,6 +8124,8 @@ append_symbol(char *name) symbol_list->hnext = hp; } +/* release_symbol --- free symbol list and optionally remove symbol from symbol table */ + void release_symbols(NODE *symlist, int keep_globals) { @@ -8194,6 +8196,7 @@ destroy_symbol(char *name) static INSTRUCTION *pool_list; static CONTEXT *curr_ctxt = NULL; +/* new_context --- create a new execution context. */ CONTEXT * new_context() @@ -8205,63 +8208,70 @@ new_context() ctxt->srcfiles.next = ctxt->srcfiles.prev = &ctxt->srcfiles; ctxt->rule_list.opcode = Op_list; ctxt->rule_list.lasti = &ctxt->rule_list; - if (curr_ctxt == NULL) { - ctxt->level = 0; - pool_list = &ctxt->pools; - symbol_list = &ctxt->symbols; - srcfiles = &ctxt->srcfiles; - rule_list = &ctxt->rule_list; - install_func = ctxt->install_func; - curr_ctxt = ctxt; - } else - ctxt->level = curr_ctxt->level + 1; /* this assumes contexts don't overlap each other ? */ - return ctxt; } +/* set_context --- change current execution context. */ -/* N.B.: new context (level > 0) inherits all command line options; - * probably should restore defaults for lint etc. - */ - -CONTEXT * +static void set_context(CONTEXT *ctxt) { - assert(curr_ctxt != NULL); - if (curr_ctxt == ctxt) - goto update; + pool_list = &ctxt->pools; + symbol_list = &ctxt->symbols; + srcfiles = &ctxt->srcfiles; + rule_list = &ctxt->rule_list; + install_func = ctxt->install_func; + curr_ctxt = ctxt; +} + +/* + * push_context: + * + * Switch to the given context after saving the current one. The set + * of active execution contexts forms a stack; the global or main context + * is at the bottom of the stack. + */ +void +push_context(CONTEXT *ctxt) +{ + ctxt->prev = curr_ctxt; /* save current source and sourceline */ - curr_ctxt->sourceline = sourceline; - curr_ctxt->source = source; + if (curr_ctxt != NULL) { + curr_ctxt->sourceline = sourceline; + curr_ctxt->source = source; + } + sourceline = 0; + source = NULL; + set_context(ctxt); +} - if (ctxt == NULL) { - assert(curr_ctxt->prev != NULL); - ctxt = curr_ctxt->prev; - } else - ctxt->prev = curr_ctxt; +/* pop_context --- switch to previous execution context. */ +void +pop_context() +{ + CONTEXT *ctxt; + + assert(curr_ctxt != NULL); + ctxt = curr_ctxt->prev; /* restore source and sourceline */ sourceline = ctxt->sourceline; source = ctxt->source; - -update: - pool_list = &ctxt->pools; - symbol_list = &ctxt->symbols; - srcfiles = &ctxt->srcfiles; - rule_list = &ctxt->rule_list; - install_func = ctxt->install_func; - curr_ctxt = ctxt; - return curr_ctxt; + set_context(ctxt); } -CONTEXT * -get_context() +/* in_main_context --- are we in the main context ? */ + +int +in_main_context() { assert(curr_ctxt != NULL); - return curr_ctxt; + return (curr_ctxt->prev == NULL); } +/* free_context --- free context structure and related data. */ + void free_context(CONTEXT *ctxt, int keep_globals) { @@ -8287,6 +8297,8 @@ free_context(CONTEXT *ctxt, int keep_globals) efree(ctxt); } +/* free_bc_internal --- free internal memory of an instruction. */ + static void free_bc_internal(INSTRUCTION *cp) { @@ -8354,7 +8366,6 @@ bcfree(INSTRUCTION *cp) pool_list->freei = cp; } - /* bcalloc --- allocate a new instruction */ INSTRUCTION * @@ -8398,6 +8409,7 @@ bcalloc(OPCODE op, int size, int srcline) return cp; } +/* free_bcpool --- free list of instruction memory pools */ static void free_bcpool(INSTRUCTION *pl) @@ -597,7 +597,7 @@ statement } | LEX_FOR '(' NAME LEX_IN simple_variable r_paren opt_nls statement { - + INSTRUCTION *ip; char *var_name = $3->lextok; if ($8 != NULL @@ -621,8 +621,8 @@ statement * and that both the loop var and array names match. */ NODE *arr = NULL; - INSTRUCTION *ip = $8->nexti->nexti; + ip = $8->nexti->nexti; if ($5->nexti->opcode == Op_push && $5->lasti == $5->nexti) arr = $5->nexti->memory; if (arr != NULL @@ -640,7 +640,8 @@ statement bcfree($4); bcfree($5); $$ = $8; - } + } else + goto regular_loop; } else { /* [ Op_push_array a ] @@ -655,8 +656,7 @@ statement * y: [Op_pop_loop ] * w: [Op_arrayfor_final ] */ - INSTRUCTION *ip; - +regular_loop: ip = $5; ip->nexti->opcode = Op_push_array; $3->opcode = Op_arrayfor_init; @@ -2063,7 +2063,7 @@ mk_program() else (void) list_prepend(end_block, ip_end); - if (get_context()->level > 0) { + if (! in_main_context()) { if (begin_block != NULL && prog_block != NULL) cp = list_merge(begin_block, prog_block); else @@ -2169,7 +2169,7 @@ parse_program(INSTRUCTION **pcode) */ ip_end = instruction(Op_no_op); - if (get_context()->level > 0) + if (! in_main_context()) ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL; else { ip_endfile = instruction(Op_no_op); @@ -3413,7 +3413,7 @@ retry: want_source = TRUE; break; case LEX_EVAL: - if (get_context()->level == 0) + if (in_main_context()) goto out; emalloc(tokkey, char *, tok - tokstart + 1, "yylex"); tokkey[0] = '@'; @@ -4259,7 +4259,7 @@ check_funcs() struct fdesc *fp, *next; int i; - if (get_context()->level > 0) + if (! in_main_context()) goto free_mem; for (i = 0; i < HASHSIZE; i++) { @@ -5056,7 +5056,7 @@ optimize_assignment(INSTRUCTION *exp) /* * N.B.: do not append Op_pop instruction to the returned * instruction list if optimized. None of these - * optimized instructions push the r-value of assignment + * optimized instructions pushes the r-value of assignment * onto the runtime stack. */ @@ -5483,6 +5483,8 @@ append_symbol(char *name) symbol_list->hnext = hp; } +/* release_symbol --- free symbol list and optionally remove symbol from symbol table */ + void release_symbols(NODE *symlist, int keep_globals) { @@ -5553,6 +5555,7 @@ destroy_symbol(char *name) static INSTRUCTION *pool_list; static CONTEXT *curr_ctxt = NULL; +/* new_context --- create a new execution context. */ CONTEXT * new_context() @@ -5564,63 +5567,70 @@ new_context() ctxt->srcfiles.next = ctxt->srcfiles.prev = &ctxt->srcfiles; ctxt->rule_list.opcode = Op_list; ctxt->rule_list.lasti = &ctxt->rule_list; - if (curr_ctxt == NULL) { - ctxt->level = 0; - pool_list = &ctxt->pools; - symbol_list = &ctxt->symbols; - srcfiles = &ctxt->srcfiles; - rule_list = &ctxt->rule_list; - install_func = ctxt->install_func; - curr_ctxt = ctxt; - } else - ctxt->level = curr_ctxt->level + 1; /* this assumes contexts don't overlap each other ? */ - return ctxt; } +/* set_context --- change current execution context. */ -/* N.B.: new context (level > 0) inherits all command line options; - * probably should restore defaults for lint etc. - */ - -CONTEXT * +static void set_context(CONTEXT *ctxt) { - assert(curr_ctxt != NULL); - if (curr_ctxt == ctxt) - goto update; + pool_list = &ctxt->pools; + symbol_list = &ctxt->symbols; + srcfiles = &ctxt->srcfiles; + rule_list = &ctxt->rule_list; + install_func = ctxt->install_func; + curr_ctxt = ctxt; +} + +/* + * push_context: + * + * Switch to the given context after saving the current one. The set + * of active execution contexts forms a stack; the global or main context + * is at the bottom of the stack. + */ +void +push_context(CONTEXT *ctxt) +{ + ctxt->prev = curr_ctxt; /* save current source and sourceline */ - curr_ctxt->sourceline = sourceline; - curr_ctxt->source = source; + if (curr_ctxt != NULL) { + curr_ctxt->sourceline = sourceline; + curr_ctxt->source = source; + } + sourceline = 0; + source = NULL; + set_context(ctxt); +} - if (ctxt == NULL) { - assert(curr_ctxt->prev != NULL); - ctxt = curr_ctxt->prev; - } else - ctxt->prev = curr_ctxt; +/* pop_context --- switch to previous execution context. */ +void +pop_context() +{ + CONTEXT *ctxt; + + assert(curr_ctxt != NULL); + ctxt = curr_ctxt->prev; /* restore source and sourceline */ sourceline = ctxt->sourceline; source = ctxt->source; - -update: - pool_list = &ctxt->pools; - symbol_list = &ctxt->symbols; - srcfiles = &ctxt->srcfiles; - rule_list = &ctxt->rule_list; - install_func = ctxt->install_func; - curr_ctxt = ctxt; - return curr_ctxt; + set_context(ctxt); } -CONTEXT * -get_context() +/* in_main_context --- are we in the main context ? */ + +int +in_main_context() { assert(curr_ctxt != NULL); - return curr_ctxt; + return (curr_ctxt->prev == NULL); } +/* free_context --- free context structure and related data. */ + void free_context(CONTEXT *ctxt, int keep_globals) { @@ -5646,6 +5656,8 @@ free_context(CONTEXT *ctxt, int keep_globals) efree(ctxt); } +/* free_bc_internal --- free internal memory of an instruction. */ + static void free_bc_internal(INSTRUCTION *cp) { @@ -5713,7 +5725,6 @@ bcfree(INSTRUCTION *cp) pool_list->freei = cp; } - /* bcalloc --- allocate a new instruction */ INSTRUCTION * @@ -5757,6 +5768,7 @@ bcalloc(OPCODE op, int size, int srcline) return cp; } +/* free_bcpool --- free list of instruction memory pools */ static void free_bcpool(INSTRUCTION *pl) @@ -78,6 +78,14 @@ double (*Log)(double) = log; #define log(x) (*Log)(x) #endif + +#define POP_TWO_SCALARS(s1, s2) \ +s2 = POP_SCALAR(); \ +s1 = POP(); \ +if ((s1)->type == Node_var_array) \ + DEREF(s2), fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)), 0 + + /* * Since we supply the version of random(), we know what * value to use here. @@ -314,9 +322,8 @@ do_index(int nargs) } #endif - s2 = POP_SCALAR(); - s1 = POP_SCALAR(); - + POP_TWO_SCALARS(s1, s2); + if (do_lint) { if ((s1->flags & (STRING|STRCUR)) == 0) lintwarn(_("index: received non-string first argument")); @@ -1192,8 +1199,7 @@ do_atan2(int nargs) NODE *t1, *t2; double d1, d2; - t2 = POP_SCALAR(); - t1 = POP_SCALAR(); + POP_TWO_SCALARS(t1, t2); if (do_lint) { if ((t1->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("atan2: received non-numeric first argument")); @@ -1861,9 +1867,7 @@ do_lshift(int nargs) uintmax_t uval, ushift, res; AWKNUM val, shift; - s2 = POP_SCALAR(); - s1 = POP_SCALAR(); - + POP_TWO_SCALARS(s1, s2); if (do_lint) { if ((s1->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("lshift: received non-numeric first argument")); @@ -1900,9 +1904,7 @@ do_rshift(int nargs) uintmax_t uval, ushift, res; AWKNUM val, shift; - s2 = POP_SCALAR(); - s1 = POP_SCALAR(); - + POP_TWO_SCALARS(s1, s2); if (do_lint) { if ((s1->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("rshift: received non-numeric first argument")); @@ -1939,9 +1941,7 @@ do_and(int nargs) uintmax_t uleft, uright, res; AWKNUM left, right; - s2 = POP_SCALAR(); - s1 = POP_SCALAR(); - + POP_TWO_SCALARS(s1, s2); if (do_lint) { if ((s1->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("and: received non-numeric first argument")); @@ -1976,9 +1976,7 @@ do_or(int nargs) uintmax_t uleft, uright, res; AWKNUM left, right; - s2 = POP_SCALAR(); - s1 = POP_SCALAR(); - + POP_TWO_SCALARS(s1, s2); if (do_lint) { if ((s1->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("or: received non-numeric first argument")); @@ -2013,8 +2011,7 @@ do_xor(int nargs) uintmax_t uleft, uright, res; AWKNUM left, right; - s2 = POP_SCALAR(); - s1 = POP_SCALAR(); + POP_TWO_SCALARS(s1, s2); left = force_number(s1); right = force_number(s2); @@ -2081,7 +2078,6 @@ do_strtonum(int nargs) AWKNUM d; tmp = POP_SCALAR(); - if ((tmp->flags & (NUMBER|NUMCUR)) != 0) d = (AWKNUM) force_number(tmp); else if (isnondecimal(tmp->stptr, use_lc_numeric)) @@ -861,7 +861,7 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) pf_data.fp = out_fp; pf_data.defn = TRUE; (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_function, - TRUE, /* sort */ + FALSE, /* sort */ &pf_data /* data */ ); } @@ -1599,9 +1599,9 @@ condition_triggered(struct condition *cndn) if (cndn->code == NULL) return TRUE; - set_context(cndn->ctxt); + push_context(cndn->ctxt); r = execute_code((volatile INSTRUCTION *) cndn->code); - set_context(NULL); /* switch to prev context */ + pop_context(); /* switch to prev context */ if (r == NULL) /* fatal error */ return FALSE; /* not triggered */ @@ -3502,7 +3502,7 @@ no_output: void post_execute(INSTRUCTION *pc, int inloop) { - if (get_context()->level > 0) + if (! in_main_context()) return; switch (pc->opcode) { @@ -3567,7 +3567,7 @@ pre_execute(INSTRUCTION **pi, int inloop) static int cant_stop = FALSE; NODE *m; - if (get_context()->level > 0) + if (! in_main_context()) return pre_execute_code(pi, inloop); cur_pc = *pi; @@ -5431,12 +5431,12 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) install_params(this_func); /* expose current function parameters to eval */ ctxt = new_context(); ctxt->install_func = append_symbol; /* keep track of newly installed globals */ - set_context(ctxt); + push_context(ctxt); (void) add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL); ret = parse_program(&code); remove_params(this_func); if (ret != 0) { - set_context(NULL); /* switch to prev context (main) */ + pop_context(); /* switch to prev context */ free_context(ctxt, FALSE /* keep_globals */); return FALSE; } @@ -5544,7 +5544,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) * globals only if fatal error in r_interpret (r == NULL). */ - set_context(NULL); /* switch to prev context (main) */ + pop_context(); /* switch to prev context */ free_context(ctxt, (ret_val != NULL)); /* free all instructions and optionally symbols */ if (ret_val != NULL) destroy_symbol("@eval"); /* destroy "@eval" */ @@ -5607,11 +5607,11 @@ parse_condition(int type, int num, char *expr) ctxt = new_context(); invalid_symbol = 0; ctxt->install_func = check_symbol; - set_context(ctxt); + push_context(ctxt); (void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL); ret = parse_program(&code); remove_params(this_func); - set_context(NULL); + pop_context(); if (ret != 0 || invalid_symbol) { free_context(ctxt, FALSE /* keep_globals */); @@ -1439,7 +1439,7 @@ unwind_stack(STACK_ITEM *sp_bottom) break; default: - if (get_context()->level == 0) + if (in_main_context()) fatal(_("unwind_stack: unexpected type `%s'"), nodetype2str(r->type)); /* else @@ -1501,11 +1501,14 @@ static void op_assign(OPCODE op) { NODE **lhs; - NODE *r; - AWKNUM x, x1, x2; + NODE *r = NULL; + AWKNUM x1, x2; #ifdef _CRAY long lx; #endif +#ifndef HAVE_FMOD + AWKNUM x; +#endif lhs = POP_ADDRESS(); x1 = force_number(*lhs); @@ -334,8 +334,8 @@ main(int argc, char **argv) /* copy argv before getopt gets to it; used to restart debugger */ save_argv(argc, argv); - /* initialize context */ - (void) new_context(); + /* initialize global (main) execution context */ + push_context(new_context()); /* option processing. ready, set, go! */ for (optopt = 0, old_optind = 1; |