diff --git a/CHANGES b/CHANGES index a31456e..05200d4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,8 @@ --- $MawkId: CHANGES,v 1.134 2010/07/24 11:59:10 tom Exp $ +-- $MawkId: CHANGES,v 1.135 2010/08/18 17:15:43 tom Exp $ Changes by Thomas E Dickey -20100718 +20100818 + add configure --enable-trace, to consolidate various debugging traces which were written to stderr. This writes to Trace.out. + modify zmalloc.c to make it simpler to use the --disable-leaks diff --git a/MANIFEST b/MANIFEST index 8077944..e831209 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,4 +1,4 @@ -MANIFEST for mawk, version t20100805 +MANIFEST for mawk, version t20100818 -------------------------------------------------------------------------------- MANIFEST this file ACKNOWLEDGMENT acknowledgements diff --git a/bi_vars.c b/bi_vars.c index 8bef680..c51ebc3 100644 --- a/bi_vars.c +++ b/bi_vars.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: bi_vars.c,v 1.8 2010/07/24 14:25:42 tom Exp $ + * $MawkId: bi_vars.c,v 1.9 2010/08/18 16:34:06 tom Exp $ * @Log: bi_vars.c,v @ * Revision 1.1.1.1 1993/07/03 18:58:09 mike * move source to cvs @@ -102,6 +102,8 @@ bi_vars_leaks(void) for (n = 0; n < NUM_BI_VAR; ++n) { switch (bi_vars[n].type) { case C_STRING: + case C_STRNUM: + case C_MBSTRN: free_STRING(string(&bi_vars[n])); break; } diff --git a/cast.c b/cast.c index 123399f..0afcd7d 100644 --- a/cast.c +++ b/cast.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: cast.c,v 1.10 2010/05/07 00:57:28 tom Exp $ + * $MawkId: cast.c,v 1.14 2010/08/13 22:21:50 tom Exp $ * @Log: cast.c,v @ * Revision 1.6 1996/08/11 22:07:50 mike * Fix small bozo in rt_error("overflow converting ...") @@ -293,6 +293,7 @@ cast_to_RE(CELL * cp) cast1_to_s(cp); p = re_compile(string(cp)); + no_leaks_re_ptr(p); free_STRING(string(cp)); cp->type = C_RE; cp->ptr = p; @@ -442,3 +443,52 @@ d_to_U(double d) return (UInt) d; return 0; } + +#ifdef NO_LEAKS +typedef struct _all_cells { + struct _all_cells *next; + char ptr; + CELL *cp; +} ALL_CELLS; + +static ALL_CELLS *all_cells; +/* + * Some regular expressions are parsed, and the pointer stored in the byte-code + * where we cannot distinguish it from other constants. Keep a list here, to + * free on exit for auditing. + */ +void +no_leaks_cell(CELL * cp) +{ + ALL_CELLS *p = calloc(1, sizeof(ALL_CELLS)); + p->next = all_cells; + p->cp = cp; + p->ptr = 0; + all_cells = p; +} + +void +no_leaks_cell_ptr(CELL * cp) +{ + ALL_CELLS *p = calloc(1, sizeof(ALL_CELLS)); + p->next = all_cells; + p->cp = cp; + p->ptr = 1; + all_cells = p; +} + +void +cell_leaks(void) +{ + while (all_cells != 0) { + ALL_CELLS *next = all_cells->next; + if (all_cells->ptr) { + zfree(all_cells->cp, sizeof(CELL)); + } else { + free_cell_data(all_cells->cp); + } + free(all_cells); + all_cells = next; + } +} +#endif diff --git a/code.c b/code.c index 8bb4c36..c954d4f 100644 --- a/code.c +++ b/code.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: code.c,v 1.26 2010/08/05 00:17:08 tom Exp $ + * $MawkId: code.c,v 1.31 2010/08/18 15:27:22 tom Exp $ * @Log: code.c,v @ * Revision 1.6 1995/06/18 19:42:13 mike * Remove some redundant declarations and add some prototypes @@ -285,141 +285,151 @@ free_codes(const char *tag, INST * base, size_t size) INST *last = base + (size / sizeof(*last)); CELL *cp; - TRACE(("free_codes(%s) base %p, size %lu\n", tag, base, size)); - for (cdp = base; cdp < last; ++cdp) { - TRACE(("code %03d:%s (%d %#x)\n", - (int) (cdp - base), - da_op_name(cdp), - cdp->op, - cdp->op)); + (void) tag; - switch ((MAWK_OPCODES) (cdp->op)) { - case AE_PUSHA: - case AE_PUSHI: - case A_CAT: - case LAE_PUSHA: - case _MATCH0: - case _MATCH1: - ++cdp; /* skip pointer */ - cp = (CELL *) (cdp->ptr); - if (cp != 0) { + TRACE(("free_codes(%s) base %p, size %lu\n", tag, base, size)); + if (base != 0 && size != 0) { + for (cdp = base; cdp < last; ++cdp) { + TRACE(("code %03d:%s (%d %#x)\n", + (int) (cdp - base), + da_op_name(cdp), + cdp->op, + cdp->op)); + + switch ((MAWK_OPCODES) (cdp->op)) { + case AE_PUSHA: + case AE_PUSHI: + ++cdp; /* skip pointer */ + cp = (CELL *) (cdp->ptr); + if (cp != 0) { + TRACE(("\tparam %p type %d\n", cp, cp->type)); + free_cell_data(cp); + } else { + TRACE(("\tparam %p type ??\n", cp)); + } + break; + case _MATCH0: + case _MATCH1: + ++cdp; /* skip pointer */ + re_destroy(cdp->ptr); + break; + case LAE_PUSHA: + case LA_PUSHA: + case A_CAT: + ++cdp; /* skip value */ + TRACE(("\tparam %d\n", cdp->op)); + break; + case A_PUSHA: + case L_PUSHA: + case L_PUSHI: + case _BUILTIN: + case _PRINT: + case _PUSHA: + case _PUSHI: + case _PUSHINT: + ++cdp; /* skip value */ + TRACE(("\tparam %p\n", cdp->ptr)); + break; + case _PUSHD: + ++cdp; /* skip value */ + TRACE(("\tparam %p\n", cdp->ptr)); + if (cdp->ptr != &double_one && cdp->ptr != &double_zero) + zfree(cdp->ptr, sizeof(double)); + break; + case F_PUSHI: + ++cdp; /* skip pointer */ + cp = (CELL *) (cdp->ptr); TRACE(("\tparam %p type %d\n", cp, cp->type)); - free_cell_data(cp); - } else { - TRACE(("\tparam %p type ??\n", cp)); + ++cdp; /* skip integer */ + break; + case _PUSHS: + ++cdp; /* skip value */ + TRACE(("\tparam %p\n", cdp->ptr)); + free_STRING((STRING *) (cdp->ptr)); + break; + case _RANGE: + cdp += 4; /* PAT1 */ + break; + case _CALL: + TRACE(("\tskipping %d\n", 1 + cdp[2].op)); + cdp += 1 + cdp[2].op; + break; + case A_DEL: + case A_TEST: + case DEL_A: + case FE_PUSHA: + case FE_PUSHI: + case F_ADD_ASG: + case F_ASSIGN: + case F_DIV_ASG: + case F_MOD_ASG: + case F_MUL_ASG: + case F_POST_DEC: + case F_POST_INC: + case F_POW_ASG: + case F_PRE_DEC: + case F_PRE_INC: + case F_PUSHA: + case F_SUB_ASG: + case NF_PUSHI: + case OL_GL: + case OL_GL_NR: + case POP_AL: + case _ADD: + case _ADD_ASG: + case _ASSIGN: + case _CAT: + case _DIV: + case _DIV_ASG: + case _EQ: + case _EXIT0: /* this does free memory... */ + case _EXIT: + case _GT: + case _GTE: + case _HALT: + case _JMAIN: + case _LT: + case _LTE: + case _MATCH2: + case _MOD: + case _MOD_ASG: + case _MUL: + case _MUL_ASG: + case _NEQ: + case _NEXT: + case _NOT: + case _OMAIN: + case _POP: + case _POST_DEC: + case _POST_INC: + case _POW: + case _POW_ASG: + case _PRE_DEC: + case _PRE_INC: + case _RET0: + case _RET: + case _STOP: + case _SUB: + case _SUB_ASG: + case _TEST: + case _UMINUS: + case _UPLUS: + break; + case _JNZ: + case _JZ: + case _LJZ: + case _LJNZ: + case _JMP: + case _PUSHC: + case ALOOP: + case LAE_PUSHI: + case SET_ALOOP: + ++cdp; /* cdp->op is literal param */ + break; } - break; - case A_PUSHA: - case L_PUSHA: - case L_PUSHI: - case LA_PUSHA: - case _BUILTIN: - case _PRINT: - case _PUSHA: - case _PUSHI: - case _PUSHINT: - ++cdp; /* skip value */ - TRACE(("\tparam %p\n", cdp->ptr)); - break; - case _PUSHD: - ++cdp; /* skip value */ - TRACE(("\tparam %p\n", cdp->ptr)); - if (cdp->ptr != &double_one && cdp->ptr != &double_zero) - zfree(cdp->ptr, sizeof(double)); - break; - case F_PUSHI: - ++cdp; /* skip pointer */ - cp = (CELL *) (cdp->ptr); - TRACE(("\tparam %p type %d\n", cp, cp->type)); - ++cdp; /* skip integer */ - break; - case _PUSHS: - ++cdp; /* skip value */ - TRACE(("\tparam %p\n", cdp->ptr)); - free_STRING((STRING *) (cdp->ptr)); - break; - case _RANGE: - cdp += 4; /* PAT1 */ - break; - case _CALL: - TRACE(("\tskipping %d\n", 1 + cdp[2].op)); - cdp += 1 + cdp[2].op; - break; - case A_DEL: - case A_TEST: - case DEL_A: - case FE_PUSHA: - case FE_PUSHI: - case F_ADD_ASG: - case F_ASSIGN: - case F_DIV_ASG: - case F_MOD_ASG: - case F_MUL_ASG: - case F_POST_DEC: - case F_POST_INC: - case F_POW_ASG: - case F_PRE_DEC: - case F_PRE_INC: - case F_PUSHA: - case F_SUB_ASG: - case NF_PUSHI: - case OL_GL: - case OL_GL_NR: - case POP_AL: - case _ADD: - case _ADD_ASG: - case _ASSIGN: - case _CAT: - case _DIV: - case _DIV_ASG: - case _EQ: - case _EXIT0: /* this does free memory... */ - case _EXIT: - case _GT: - case _GTE: - case _HALT: - case _JMAIN: - case _LT: - case _LTE: - case _MATCH2: - case _MOD: - case _MOD_ASG: - case _MUL: - case _MUL_ASG: - case _NEQ: - case _NEXT: - case _NOT: - case _OMAIN: - case _POP: - case _POST_DEC: - case _POST_INC: - case _POW: - case _POW_ASG: - case _PRE_DEC: - case _PRE_INC: - case _RET0: - case _RET: - case _STOP: - case _SUB: - case _SUB_ASG: - case _TEST: - case _UMINUS: - case _UPLUS: - break; - case _JNZ: - case _JZ: - case _LJZ: - case _LJNZ: - case _JMP: - case _PUSHC: - case ALOOP: - case LAE_PUSHI: - case SET_ALOOP: - ++cdp; /* cdp->op is literal param */ - break; } + zfree(base, size); } - zfree(base, size); } void diff --git a/execute.c b/execute.c index aaceee9..3048b75 100644 --- a/execute.c +++ b/execute.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: execute.c,v 1.20 2010/08/04 23:02:35 tom Exp $ + * $MawkId: execute.c,v 1.23 2010/08/18 17:09:02 tom Exp $ * @Log: execute.c,v @ * Revision 1.13 1996/02/01 04:39:40 mike * dynamic array scheme @@ -269,7 +269,6 @@ execute(INST * cdp, /* code ptr, start execution here */ */ t = field_addr_to_index(cp); if (t > nf) { - cell_destroy(cp); cp->type = C_STRING; cp->ptr = (PTR) & null_str; null_str.ref_cnt++; @@ -1081,6 +1080,7 @@ execute(INST * cdp, /* code ptr, start execution here */ cast_to_re((sp + 1)->ptr)); free_STRING(string(sp)); + no_leaks_re_ptr((sp + 1)->ptr); sp->type = C_DOUBLE; sp->dval = t ? 1.0 : 0.0; break; @@ -1482,8 +1482,7 @@ DB_cell_destroy(CELL * cp) case C_MBSTRN: case C_STRING: case C_STRNUM: - if (--string(cp)->ref_cnt == 0) - zfree(string(cp), string(cp)->len + STRING_OH); + free_STRING(string(cp)); break; case C_RE: diff --git a/field.c b/field.c index 3e005b7..375e608 100644 --- a/field.c +++ b/field.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: field.c,v 1.21 2010/08/04 23:35:07 tom Exp $ + * $MawkId: field.c,v 1.24 2010/08/17 08:56:01 tom Exp $ * @Log: field.c,v @ * Revision 1.5 1995/06/18 19:17:47 mike * Create a type Int which on most machines is an int, but on machines diff --git a/files.c b/files.c index 30a0d6a..99380e0 100644 --- a/files.c +++ b/files.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: files.c,v 1.17 2010/07/24 13:43:03 tom Exp $ + * $MawkId: files.c,v 1.19 2010/08/06 08:48:09 tom Exp $ * * @Log: files.c,v @ * Revision 1.9 1996/01/14 17:14:10 mike @@ -136,7 +136,7 @@ free_filenode(FILE_NODE * p) PTR file_find(STRING * sval, int type) { - register FILE_NODE *p = file_list; + FILE_NODE *p = file_list; FILE_NODE *q = (FILE_NODE *) 0; char *name = sval->str; const char *ostr; @@ -239,7 +239,7 @@ int file_close(STRING * sval) { FILE_NODE dummy; - register FILE_NODE *p; + FILE_NODE *p; FILE_NODE *q = &dummy; /* trails p */ FILE_NODE *hold; char *name = sval->str; @@ -321,7 +321,7 @@ int file_flush(STRING * sval) { int ret = -1; - register FILE_NODE *p = file_list; + FILE_NODE *p = file_list; size_t len = sval->len; char *str = sval->str; @@ -378,6 +378,7 @@ void close_out_pipes(void) { FILE_NODE *p = file_list; + FILE_NODE *q = 0; while (p) { @@ -386,13 +387,17 @@ close_out_pipes(void) /* if another error occurs we do not want to be called for the same file again */ - file_list = p->link; + if (q != 0) + q->link = p->link; + else + file_list = p->link; close_error(p); } else if (p->type == PIPE_OUT) { wait_for(p->pid); } } + q = p; p = p->link; } } @@ -403,7 +408,7 @@ close_out_pipes(void) void close_fake_pipes(void) { - register FILE_NODE *p = file_list; + FILE_NODE *p = file_list; char xbuff[100]; /* close input pipes first to free descriptors for children */ @@ -471,8 +476,9 @@ get_pipe(char *name, int type, int *pid_ptr) break; } - return type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) : - (PTR) fdopen(local_fd, "w"); + return ((type == PIPE_IN) + ? (PTR) FINdopen(local_fd, 0) + : (PTR) fdopen(local_fd, "w")); } /*------------ children ------------------*/ @@ -491,7 +497,7 @@ static struct child { static void add_to_child_list(int pid, int exit_status) { - register struct child *p = ZMALLOC(struct child); + struct child *p = ZMALLOC(struct child); p->pid = pid; p->exit_status = exit_status; @@ -503,7 +509,7 @@ static struct child * remove_from_child_list(int pid) { struct child dummy; - register struct child *p; + struct child *p; struct child *q = &dummy; dummy.link = p = child_list; @@ -643,6 +649,9 @@ close_error(FILE_NODE * p) { TRACE(("close_error(%s)\n", p->name->str)); errmsg(errno, "close failed on file %s", p->name->str); +#ifdef NO_LEAKS + free_filenode(p); +#endif mawk_exit(2); } @@ -650,6 +659,7 @@ close_error(FILE_NODE * p) void files_leaks(void) { + TRACE(("files_leaks\n")); while (file_list != 0) { FILE_NODE *p = file_list; file_list = p->link; diff --git a/fin.c b/fin.c index 036db86..fb23419 100644 --- a/fin.c +++ b/fin.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: fin.c,v 1.28 2010/07/30 00:02:43 tom Exp $ + * $MawkId: fin.c,v 1.31 2010/08/18 16:41:35 tom Exp $ * @Log: fin.c,v @ * Revision 1.10 1995/12/24 22:23:22 mike * remove errmsg() from inside FINopen @@ -91,17 +91,32 @@ static FIN *next_main(int); static char *enlarge_fin_buffer(FIN *); int is_cmdline_assign(char *); /* also used by init */ +/* this is how we mark EOF on main_fin */ +static char dead_buff = 0; +static FIN dead_main = +{0, (FILE *) 0, &dead_buff, &dead_buff, &dead_buff, + 1, EOF_FLAG}; + +static void +free_fin_data(FIN * fin) +{ + if (fin != &dead_main) { + zfree(fin->buff, (size_t) (fin->nbuffs * BUFFSZ + 1)); + ZFREE(fin); + } +} + /* convert file-descriptor to FIN*. It's the main stream if main_flag is set */ FIN * FINdopen(int fd, int main_flag) { - register FIN *fin = ZMALLOC(FIN); + FIN *fin = ZMALLOC(FIN); fin->fd = fd; fin->flags = main_flag ? (MAIN_FLAG | START_FLAG) : START_FLAG; - fin->buffp = fin->buff = (char *) zmalloc((size_t) (BUFFSZ + 1)); + fin->buffp = fin->buff = (char *) zmalloc((size_t) BUFFSZ + 1); fin->limit = fin->buffp; fin->nbuffs = 1; fin->buff[0] = 0; @@ -109,14 +124,16 @@ FINdopen(int fd, int main_flag) if ((isatty(fd) && rs_shadow.type == SEP_CHAR && rs_shadow.c == '\n') || interactive_flag) { /* interactive, i.e., line buffer this file */ - if (fd == 0) + if (fd == 0) { fin->fp = stdin; - else if (!(fin->fp = fdopen(fd, "r"))) { + } else if (!(fin->fp = fdopen(fd, "r"))) { errmsg(errno, "fdopen failed"); + free_fin_data(fin); mawk_exit(2); } - } else + } else { fin->fp = (FILE *) 0; + } return fin; } @@ -129,6 +146,7 @@ FINdopen(int fd, int main_flag) FIN * FINopen(char *filename, int main_flag) { + FIN *result = 0; int fd; int oflag = O_RDONLY; @@ -143,13 +161,11 @@ FINopen(char *filename, int main_flag) if (bm) setmode(0, O_BINARY); #endif - return FINdopen(0, main_flag); + result = FINdopen(0, main_flag); + } else if ((fd = open(filename, oflag, 0)) != -1) { + result = FINdopen(fd, main_flag); } - - if ((fd = open(filename, oflag, 0)) == -1) - return (FIN *) 0; - else - return FINdopen(fd, main_flag); + return result; } /* frees the buffer and fd, but leaves FIN structure until @@ -450,8 +466,10 @@ next_main(int open_flag) /* called by open_main() if on */ argval.type = C_NOINIT; c_argi.type = C_DOUBLE; - if (main_fin) + if (main_fin) { FINclose(main_fin); + main_fin = 0; + } /* FILENAME and FNR don't change unless we really open a new file */ @@ -469,7 +487,9 @@ next_main(int open_flag) /* called by open_main() if on */ /* make a copy so we can cast w/o side effect */ cell_destroy(&argval); cp = cellcpy(&argval, cp0); +#ifndef NO_LEAKS cell_destroy(cp0); +#endif if (cp->type < C_STRING) cast1_to_s(cp); @@ -512,17 +532,8 @@ next_main(int open_flag) /* called by open_main() if on */ return main_fin; } - /* real failure */ - { - /* this is how we mark EOF on main_fin */ - static char dead_buff = 0; - static FIN dead_main = - {0, (FILE *) 0, &dead_buff, &dead_buff, &dead_buff, - 1, EOF_FLAG}; - - return main_fin = &dead_main; - /* since MAIN_FLAG is not set, FINgets won't call next_main() */ - } + return main_fin = &dead_main; + /* since MAIN_FLAG is not set, FINgets won't call next_main() */ } int @@ -590,3 +601,15 @@ is_cmdline_assign(char *s) } return 1; } + +#ifdef NO_LEAKS +void +fin_leaks(void) +{ + TRACE(("fin_leaks\n")); + if (main_fin) { + free_fin_data(main_fin); + main_fin = 0; + } +} +#endif diff --git a/hash.c b/hash.c index ce25592..2a1750b 100644 --- a/hash.c +++ b/hash.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: hash.c,v 1.14 2010/08/05 09:13:01 tom Exp $ + * $MawkId: hash.c,v 1.17 2010/08/13 10:52:42 tom Exp $ * @Log: hash.c,v @ * Revision 1.3 1994/10/08 19:15:43 mike * remove SM_DOS @@ -73,6 +73,12 @@ typedef struct hash { static HASHNODE *hash_table[HASH_PRIME]; +#ifdef NO_LEAKS +static void free_hashnode(HASHNODE *); +#else +#define free_hashnode(p) zfree(delete(p->symtab.name), sizeof(HASHNODE)) +#endif + /* insert a string in the symbol table. Caller knows the symbol is not there @@ -87,6 +93,9 @@ insert(const char *s) p->link = hash_table[h = hash(s) % HASH_PRIME]; p->symtab.name = s; +#ifdef NO_LEAKS + p->symtab.free_name = 0; +#endif hash_table[h] = p; return &p->symtab; } @@ -108,6 +117,9 @@ find(const char *s) p = ZMALLOC(HASHNODE); p->symtab.type = ST_NONE; p->symtab.name = strcpy(zmalloc(strlen(s) + 1), s); +#ifdef NO_LEAKS + p->symtab.free_name = 1; +#endif break; } @@ -191,7 +203,7 @@ save_id(const char *s) return &q->symtab; } -/* restore all global indentifiers */ +/* restore all global identifiers */ void restore_ids(void) { @@ -203,7 +215,7 @@ restore_ids(void) while (q) { p = q; q = q->link; - zfree(delete(p->symtab.name), sizeof(HASHNODE)); + free_hashnode(p); p->link = hash_table[h = last_hash]; hash_table[h] = p; } @@ -262,42 +274,64 @@ reverse_find(int type, PTR ptr) } #ifdef NO_LEAKS +static void +free_symtab_name(HASHNODE * p) +{ + if (p->symtab.free_name) { + zfree((PTR) (p->symtab.name), strlen(p->symtab.name) + 1); + } +} + +static void +free_hashnode(HASHNODE * p) +{ + CELL *cp; + + TRACE(("...deleting hash %p (%p) %s %d\n", p, &(p->symtab), + p->symtab.name, p->symtab.type)); + p = delete(p->symtab.name); + switch (p->symtab.type) { + case ST_FUNCT: + free_codes(p->symtab.name, + p->symtab.stval.fbp->code, + p->symtab.stval.fbp->size); + if (p->symtab.stval.fbp->nargs) + zfree(p->symtab.stval.fbp->typev, p->symtab.stval.fbp->nargs); + zfree(p->symtab.stval.fbp, sizeof(FBLOCK)); + break; + case ST_NONE: + break; + case ST_VAR: + cp = p->symtab.stval.cp; + if (cp != 0 + && (cp < bi_vars || cp > bi_vars + NUM_BI_VAR)) { + switch (cp->type) { + case C_STRING: + case C_STRNUM: + case C_MBSTRN: + free_STRING(string(cp)); + break; + } + zfree(cp, sizeof(CELL)); + } + break; + default: + break; + } + free_symtab_name(p); + zfree(p, sizeof(HASHNODE)); +} + void hash_leaks(void) { int i; HASHNODE *p; - CELL *cp; TRACE(("hash_leaks\n")); for (i = 0; i < HASH_PRIME; i++) { while ((p = hash_table[i]) != 0) { - TRACE(("...deleting hash %s %d\n", p->symtab.name, p->symtab.type)); - p = delete(p->symtab.name); - switch (p->symtab.type) { - case ST_FUNCT: - free_codes(p->symtab.name, - p->symtab.stval.fbp->code, - p->symtab.stval.fbp->size); - zfree(p->symtab.stval.fbp, sizeof(FBLOCK)); - break; - case ST_VAR: - cp = p->symtab.stval.cp; - if (cp != 0 - && (cp < bi_vars || cp > bi_vars + NUM_BI_VAR)) { - switch (cp->type) { - case C_STRING: - case C_STRNUM: - case C_MBSTRN: - free_STRING(string(cp)); - break; - } - zfree((PTR) (p->symtab.name), strlen(p->symtab.name) + 1); - zfree(cp, sizeof(CELL)); - } - break; - } - zfree(p, sizeof(HASHNODE)); + free_hashnode(p); } } } diff --git a/main.c b/main.c index 0dd5d08..31621de 100644 --- a/main.c +++ b/main.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: main.c,v 1.20 2010/08/03 00:50:24 tom Exp $ + * $MawkId: main.c,v 1.22 2010/08/08 23:15:32 tom Exp $ * @Log: main.c,v @ * Revision 1.4 1995/06/09 22:57:19 mike * parse() no longer returns on error @@ -93,11 +93,14 @@ mawk_exit(int x) #ifdef NO_LEAKS code_leaks(); scan_leaks(); + cell_leaks(); + re_leaks(); rexp_leaks(); bi_vars_leaks(); hash_leaks(); array_leaks(); files_leaks(); + fin_leaks(); field_leaks(); zmalloc_leaks(); #if OPT_TRACE > 0 diff --git a/mawk.h b/mawk.h index 0fcf840..654b70a 100644 --- a/mawk.h +++ b/mawk.h @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: mawk.h,v 1.32 2010/08/04 23:02:20 tom Exp $ + * $MawkId: mawk.h,v 1.36 2010/08/18 17:01:04 tom Exp $ * @Log: mawk.h,v @ * Revision 1.10 1996/08/25 19:31:04 mike * Added work-around for solaris strtod overflow bug. @@ -144,8 +144,9 @@ extern unsigned rt_nr, rt_fnr; /* ditto */ #define cell_destroy(cp) \ do { \ if ( (cp)->type >= C_STRING && \ - -- string(cp)->ref_cnt == 0 ) \ - zfree(string(cp),string(cp)->len+STRING_OH); \ + (cp)->type <= C_MBSTRN ) { \ + free_STRING(string(cp)); \ + } \ } while (0) #endif @@ -217,21 +218,35 @@ extern void Trace(const char *,...) GCC_PRINTFLIKE(1,2); #endif #ifdef NO_LEAKS + extern const char *da_op_name(INST *); extern void free_cell_data(CELL *); extern void free_codes(const char *, INST *, size_t); +extern void no_leaks_cell(CELL *); +extern void no_leaks_cell_ptr(CELL *); +extern void no_leaks_re_ptr(PTR); + extern void array_leaks(void); extern void bi_vars_leaks(void); +extern void cell_leaks(void); extern void code_leaks(void); extern void field_leaks(void); extern void files_leaks(void); +extern void fin_leaks(void); extern void hash_leaks(void); +extern void re_leaks(void); extern void rexp_leaks(void); extern void scan_leaks(void); extern void trace_leaks(void); extern void zmalloc_leaks(void); + #else + #define free_codes(tag, base, size) zfree(base, size) +#define no_leaks_cell(ptr) /* nothing */ +#define no_leaks_cell_ptr(ptr) /* nothing */ +#define no_leaks_re_ptr(ptr) /* nothing */ + #endif /* diff --git a/memory.c b/memory.c index ddbc168..cc394d2 100644 --- a/memory.c +++ b/memory.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: memory.c,v 1.6 2010/05/07 00:41:10 tom Exp $ + * $MawkId: memory.c,v 1.7 2010/08/18 17:10:01 tom Exp $ * @Log: memory.c,v @ * Revision 1.2 1993/07/17 13:23:08 mike * indent and general code cleanup @@ -97,8 +97,10 @@ new_STRING(const char *s) void DB_free_STRING(STRING * sval) { - if (--sval->ref_cnt == 0) + if (--sval->ref_cnt == 0 && + sval != &null_str) { zfree(sval, sval->len + STRING_OH); + } } #endif diff --git a/memory.h b/memory.h index 8a2b57e..9996c74 100644 --- a/memory.h +++ b/memory.h @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: memory.h,v 1.7 2010/05/07 00:41:27 tom Exp $ + * $MawkId: memory.h,v 1.8 2010/08/18 17:02:12 tom Exp $ * @Log: memory.h,v @ * Revision 1.1.1.1 1993/07/03 18:58:17 mike * move source to cvs @@ -44,8 +44,9 @@ void DB_free_STRING(STRING *); #define free_STRING(sval) \ do { \ - if ( -- (sval)->ref_cnt == 0 ) \ - zfree(sval, (sval)->len+STRING_OH) ; \ + if ( -- (sval)->ref_cnt == 0 && \ + sval != &null_str ) \ + zfree(sval, (sval)->len + STRING_OH) ; \ } while (0) #endif diff --git a/package/debian/changelog b/package/debian/changelog index 49b09f9..2dc872d 100644 --- a/package/debian/changelog +++ b/package/debian/changelog @@ -1,4 +1,4 @@ -mawk-cur (1.3.4-20100718) unstable; urgency=low +mawk-cur (1.3.4-20100818) unstable; urgency=low * bug-fixes diff --git a/package/mawk.spec b/package/mawk.spec index 65722c3..ad286ad 100644 --- a/package/mawk.spec +++ b/package/mawk.spec @@ -1,8 +1,8 @@ Summary: mawk - pattern scanning and text processing language %define AppProgram mawk %define AppVersion 1.3.4 -%define AppRelease 20100718 -# $MawkId: mawk.spec,v 1.4 2010/07/18 09:26:17 tom Exp $ +%define AppRelease 20100818 +# $MawkId: mawk.spec,v 1.5 2010/08/18 23:44:28 tom Exp $ Name: %{AppProgram} Version: %{AppVersion} Release: %{AppRelease} diff --git a/parse.c b/parse.c index cb3bd6e..655d388 100644 --- a/parse.c +++ b/parse.c @@ -1155,7 +1155,7 @@ YYSTYPE yylval; /* variables for the parser stack */ static YYSTACKDATA yystack; -#line 1148 "parse.y" +#line 1155 "parse.y" /* resize the code for a user function */ @@ -1350,6 +1350,7 @@ static void RE_as_arg(void) cp->type = C_RE ; cp->ptr = code_ptr[1].ptr ; code2(_PUSHC, cp) ; + no_leaks_cell_ptr(cp); } /* reset the active_code back to the MAIN block */ @@ -1393,7 +1394,7 @@ parse(void) if ( compile_error_count != 0 ) mawk_exit(2) ; if ( dump_code_flag ) { dump_code() ; mawk_exit(0) ; } } -#line 1396 "y.tab.c" +#line 1397 "y.tab.c" #if YYDEBUG #include /* needed for printf */ @@ -1789,6 +1790,7 @@ case 46: cp->type = C_STRING ; cp->ptr = p3[1].ptr ; cast_to_RE(cp) ; + no_leaks_re_ptr(cp->ptr) ; code_ptr -= 2 ; code2(_MATCH1, cp->ptr) ; ZFREE(cp) ; @@ -1801,51 +1803,51 @@ case 46: } break; case 47: -#line 360 "parse.y" +#line 361 "parse.y" { code1(_TEST) ; code_jmp(_LJNZ, (INST*)0) ; } break; case 48: -#line 364 "parse.y" +#line 365 "parse.y" { code1(_TEST) ; patch_jmp(code_ptr) ; } break; case 49: -#line 367 "parse.y" +#line 368 "parse.y" { code1(_TEST) ; code_jmp(_LJZ, (INST*)0) ; } break; case 50: -#line 371 "parse.y" +#line 372 "parse.y" { code1(_TEST) ; patch_jmp(code_ptr) ; } break; case 51: -#line 373 "parse.y" +#line 374 "parse.y" { code_jmp(_JZ, (INST*)0) ; } break; case 52: -#line 374 "parse.y" +#line 375 "parse.y" { code_jmp(_JMP, (INST*)0) ; } break; case 53: -#line 376 "parse.y" +#line 377 "parse.y" { patch_jmp(code_ptr) ; patch_jmp(CDP(yystack.l_mark[0].start)) ; } break; case 55: -#line 381 "parse.y" +#line 382 "parse.y" { code1(_CAT) ; } break; case 56: -#line 385 "parse.y" +#line 386 "parse.y" { yyval.start = code_offset ; code2(_PUSHD, yystack.l_mark[0].ptr) ; } break; case 57: -#line 387 "parse.y" +#line 388 "parse.y" { yyval.start = code_offset ; code2(_PUSHS, yystack.l_mark[0].ptr) ; } break; case 58: -#line 389 "parse.y" +#line 390 "parse.y" { check_var(yystack.l_mark[0].stp) ; yyval.start = code_offset ; if ( is_local(yystack.l_mark[0].stp) ) @@ -1854,51 +1856,54 @@ case 58: } break; case 59: -#line 397 "parse.y" +#line 398 "parse.y" { yyval.start = yystack.l_mark[-1].start ; } break; case 60: -#line 401 "parse.y" - { yyval.start = code_offset ; code2(_MATCH0, yystack.l_mark[0].ptr) ; } +#line 402 "parse.y" + { yyval.start = code_offset ; + code2(_MATCH0, yystack.l_mark[0].ptr) ; + no_leaks_re_ptr(yystack.l_mark[0].ptr); + } break; case 61: -#line 404 "parse.y" +#line 408 "parse.y" { code1(_ADD) ; } break; case 62: -#line 405 "parse.y" +#line 409 "parse.y" { code1(_SUB) ; } break; case 63: -#line 406 "parse.y" +#line 410 "parse.y" { code1(_MUL) ; } break; case 64: -#line 407 "parse.y" +#line 411 "parse.y" { code1(_DIV) ; } break; case 65: -#line 408 "parse.y" +#line 412 "parse.y" { code1(_MOD) ; } break; case 66: -#line 409 "parse.y" +#line 413 "parse.y" { code1(_POW) ; } break; case 67: -#line 411 "parse.y" +#line 415 "parse.y" { yyval.start = yystack.l_mark[0].start ; code1(_NOT) ; } break; case 68: -#line 413 "parse.y" +#line 417 "parse.y" { yyval.start = yystack.l_mark[0].start ; code1(_UPLUS) ; } break; case 69: -#line 415 "parse.y" +#line 419 "parse.y" { yyval.start = yystack.l_mark[0].start ; code1(_UMINUS) ; } break; case 71: -#line 420 "parse.y" +#line 424 "parse.y" { check_var(yystack.l_mark[-1].stp) ; yyval.start = code_offset ; code_address(yystack.l_mark[-1].stp) ; @@ -1908,46 +1913,46 @@ case 71: } break; case 72: -#line 428 "parse.y" +#line 432 "parse.y" { yyval.start = yystack.l_mark[0].start ; if ( yystack.l_mark[-1].ival == '+' ) code1(_PRE_INC) ; else code1(_PRE_DEC) ; } break; case 73: -#line 435 "parse.y" +#line 439 "parse.y" { if (yystack.l_mark[0].ival == '+' ) code1(F_POST_INC ) ; else code1(F_POST_DEC) ; } break; case 74: -#line 439 "parse.y" +#line 443 "parse.y" { yyval.start = yystack.l_mark[0].start ; if ( yystack.l_mark[-1].ival == '+' ) code1(F_PRE_INC) ; else code1( F_PRE_DEC) ; } break; case 75: -#line 446 "parse.y" +#line 450 "parse.y" { yyval.start = code_offset ; check_var(yystack.l_mark[0].stp) ; code_address(yystack.l_mark[0].stp) ; } break; case 76: -#line 454 "parse.y" +#line 458 "parse.y" { yyval.ival = 0 ; } break; case 78: -#line 459 "parse.y" +#line 463 "parse.y" { yyval.ival = 1 ; } break; case 79: -#line 461 "parse.y" +#line 465 "parse.y" { yyval.ival = yystack.l_mark[-2].ival + 1 ; } break; case 80: -#line 466 "parse.y" +#line 470 "parse.y" { BI_REC *p = yystack.l_mark[-4].bip ; yyval.start = yystack.l_mark[-3].start ; if ( (int)p->min_args > yystack.l_mark[-1].ival || (int)p->max_args < yystack.l_mark[-1].ival ) @@ -1960,7 +1965,7 @@ case 80: } break; case 81: -#line 477 "parse.y" +#line 481 "parse.y" { yyval.start = code_offset ; code1(_PUSHINT) ; code1(0) ; @@ -1968,11 +1973,11 @@ case 81: } break; case 82: -#line 486 "parse.y" +#line 490 "parse.y" { yyval.start = code_offset ; } break; case 83: -#line 491 "parse.y" +#line 495 "parse.y" { code2(_PRINT, yystack.l_mark[-4].fp) ; if ( yystack.l_mark[-4].fp == bi_printf && yystack.l_mark[-2].ival == 0 ) compile_error("no arguments in call to printf") ; @@ -1981,72 +1986,72 @@ case 83: } break; case 84: -#line 499 "parse.y" +#line 503 "parse.y" { yyval.fp = bi_print ; print_flag = 1 ;} break; case 85: -#line 500 "parse.y" +#line 504 "parse.y" { yyval.fp = bi_printf ; print_flag = 1 ; } break; case 86: -#line 503 "parse.y" +#line 507 "parse.y" { code2op(_PUSHINT, yystack.l_mark[0].ival) ; } break; case 87: -#line 505 "parse.y" +#line 509 "parse.y" { yyval.ival = yystack.l_mark[-1].arg2p->cnt ; zfree(yystack.l_mark[-1].arg2p,sizeof(ARG2_REC)) ; code2op(_PUSHINT, yyval.ival) ; } break; case 88: -#line 509 "parse.y" +#line 513 "parse.y" { yyval.ival=0 ; code2op(_PUSHINT, 0) ; } break; case 89: -#line 513 "parse.y" +#line 517 "parse.y" { yyval.arg2p = (ARG2_REC*) zmalloc(sizeof(ARG2_REC)) ; yyval.arg2p->start = yystack.l_mark[-2].start ; yyval.arg2p->cnt = 2 ; } break; case 90: -#line 518 "parse.y" +#line 522 "parse.y" { yyval.arg2p = yystack.l_mark[-2].arg2p ; yyval.arg2p->cnt++ ; } break; case 92: -#line 523 "parse.y" +#line 527 "parse.y" { code2op(_PUSHINT, yystack.l_mark[-1].ival) ; } break; case 93: -#line 530 "parse.y" +#line 534 "parse.y" { yyval.start = yystack.l_mark[-1].start ; eat_nl() ; code_jmp(_JZ, (INST*)0) ; } break; case 94: -#line 535 "parse.y" +#line 539 "parse.y" { patch_jmp( code_ptr ) ; } break; case 95: -#line 538 "parse.y" +#line 542 "parse.y" { eat_nl() ; code_jmp(_JMP, (INST*)0) ; } break; case 96: -#line 543 "parse.y" +#line 547 "parse.y" { patch_jmp(code_ptr) ; patch_jmp(CDP(yystack.l_mark[0].start)) ; } break; case 97: -#line 552 "parse.y" +#line 556 "parse.y" { eat_nl() ; BC_new() ; } break; case 98: -#line 557 "parse.y" +#line 561 "parse.y" { yyval.start = yystack.l_mark[-5].start ; code_jmp(_JNZ, CDP(yystack.l_mark[-5].start)) ; BC_clear(code_ptr, CDP(yystack.l_mark[-2].start)) ; } break; case 99: -#line 563 "parse.y" +#line 567 "parse.y" { eat_nl() ; BC_new() ; yyval.start = yystack.l_mark[-1].start ; @@ -2065,7 +2070,7 @@ case 99: } break; case 100: -#line 583 "parse.y" +#line 587 "parse.y" { int saved_offset ; int len ; @@ -2089,7 +2094,7 @@ case 100: } break; case 101: -#line 609 "parse.y" +#line 613 "parse.y" { int cont_offset = code_offset ; unsigned len = code_pop(code_ptr) ; @@ -2113,19 +2118,19 @@ case 101: } break; case 102: -#line 632 "parse.y" +#line 636 "parse.y" { yyval.start = code_offset ; } break; case 103: -#line 634 "parse.y" +#line 638 "parse.y" { yyval.start = yystack.l_mark[-1].start ; code1(_POP) ; } break; case 104: -#line 637 "parse.y" +#line 641 "parse.y" { yyval.start = code_offset ; } break; case 105: -#line 639 "parse.y" +#line 643 "parse.y" { if ( code_ptr - 2 == CDP(yystack.l_mark[-1].start) && code_ptr[-2].op == _PUSHD && @@ -2142,13 +2147,13 @@ case 105: } break; case 106: -#line 656 "parse.y" +#line 660 "parse.y" { eat_nl() ; BC_new() ; code_push((INST*)0,0, scope, active_funct) ; } break; case 107: -#line 660 "parse.y" +#line 664 "parse.y" { INST *p1 = CDP(yystack.l_mark[-1].start) ; eat_nl() ; BC_new() ; @@ -2158,14 +2163,14 @@ case 107: } break; case 108: -#line 673 "parse.y" +#line 677 "parse.y" { check_array(yystack.l_mark[0].stp) ; code_array(yystack.l_mark[0].stp) ; code1(A_TEST) ; } break; case 109: -#line 678 "parse.y" +#line 682 "parse.y" { yyval.start = yystack.l_mark[-3].arg2p->start ; code2op(A_CAT, yystack.l_mark[-3].arg2p->cnt) ; zfree(yystack.l_mark[-3].arg2p, sizeof(ARG2_REC)) ; @@ -2176,7 +2181,7 @@ case 109: } break; case 110: -#line 689 "parse.y" +#line 693 "parse.y" { if ( yystack.l_mark[-1].ival > 1 ) { code2op(A_CAT, yystack.l_mark[-1].ival) ; } @@ -2189,7 +2194,7 @@ case 110: } break; case 111: -#line 702 "parse.y" +#line 706 "parse.y" { if ( yystack.l_mark[-1].ival > 1 ) { code2op(A_CAT, yystack.l_mark[-1].ival) ; } @@ -2202,7 +2207,7 @@ case 111: } break; case 112: -#line 714 "parse.y" +#line 718 "parse.y" { if ( yystack.l_mark[-2].ival > 1 ) { code2op(A_CAT,yystack.l_mark[-2].ival) ; } @@ -2218,7 +2223,7 @@ case 112: } break; case 113: -#line 731 "parse.y" +#line 735 "parse.y" { yyval.start = yystack.l_mark[-4].start ; if ( yystack.l_mark[-2].ival > 1 ) { code2op(A_CAT, yystack.l_mark[-2].ival) ; } @@ -2228,7 +2233,7 @@ case 113: } break; case 114: -#line 739 "parse.y" +#line 743 "parse.y" { yyval.start = code_offset ; check_array(yystack.l_mark[-1].stp) ; @@ -2237,7 +2242,7 @@ case 114: } break; case 115: -#line 750 "parse.y" +#line 754 "parse.y" { eat_nl() ; BC_new() ; yyval.start = code_offset ; @@ -2250,7 +2255,7 @@ case 115: } break; case 116: -#line 764 "parse.y" +#line 768 "parse.y" { INST *p2 = CDP(yystack.l_mark[0].start) ; @@ -2261,11 +2266,11 @@ case 116: } break; case 117: -#line 781 "parse.y" +#line 785 "parse.y" { yyval.start = code_offset ; code2(F_PUSHA, yystack.l_mark[0].cp) ; } break; case 118: -#line 783 "parse.y" +#line 787 "parse.y" { check_var(yystack.l_mark[0].stp) ; yyval.start = code_offset ; if ( is_local(yystack.l_mark[0].stp) ) @@ -2276,7 +2281,7 @@ case 118: } break; case 119: -#line 792 "parse.y" +#line 796 "parse.y" { if ( yystack.l_mark[-1].ival > 1 ) { code2op(A_CAT, yystack.l_mark[-1].ival) ; } @@ -2292,62 +2297,62 @@ case 119: } break; case 120: -#line 806 "parse.y" +#line 810 "parse.y" { yyval.start = yystack.l_mark[0].start ; CODE_FE_PUSHA() ; } break; case 121: -#line 808 "parse.y" +#line 812 "parse.y" { yyval.start = yystack.l_mark[-1].start ; } break; case 122: -#line 812 "parse.y" +#line 816 "parse.y" { field_A2I() ; } break; case 123: -#line 815 "parse.y" +#line 819 "parse.y" { code1(F_ASSIGN) ; } break; case 124: -#line 816 "parse.y" +#line 820 "parse.y" { code1(F_ADD_ASG) ; } break; case 125: -#line 817 "parse.y" +#line 821 "parse.y" { code1(F_SUB_ASG) ; } break; case 126: -#line 818 "parse.y" +#line 822 "parse.y" { code1(F_MUL_ASG) ; } break; case 127: -#line 819 "parse.y" +#line 823 "parse.y" { code1(F_DIV_ASG) ; } break; case 128: -#line 820 "parse.y" +#line 824 "parse.y" { code1(F_MOD_ASG) ; } break; case 129: -#line 821 "parse.y" +#line 825 "parse.y" { code1(F_POW_ASG) ; } break; case 130: -#line 828 "parse.y" +#line 832 "parse.y" { code2(_BUILTIN, bi_split) ; } break; case 131: -#line 832 "parse.y" +#line 836 "parse.y" { yyval.start = yystack.l_mark[-2].start ; check_array(yystack.l_mark[0].stp) ; code_array(yystack.l_mark[0].stp) ; } break; case 132: -#line 839 "parse.y" +#line 843 "parse.y" { code2(_PUSHI, &fs_shadow) ; } break; case 133: -#line 841 "parse.y" +#line 845 "parse.y" { if ( CDP(yystack.l_mark[-1].start) == code_ptr - 2 ) { @@ -2362,18 +2367,19 @@ case 133: cast_for_split(cp) ; code_ptr[-2].op = _PUSHC ; code_ptr[-1].ptr = (PTR) cp ; + no_leaks_cell(cp); } } } break; case 134: -#line 865 "parse.y" +#line 870 "parse.y" { yyval.start = yystack.l_mark[-3].start ; code2(_BUILTIN, bi_match) ; } break; case 135: -#line 872 "parse.y" +#line 877 "parse.y" { INST *p1 = CDP(yystack.l_mark[0].start) ; @@ -2389,30 +2395,31 @@ case 135: cast_to_RE(cp) ; p1->op = _PUSHC ; p1[1].ptr = (PTR) cp ; + no_leaks_cell(cp); } } } break; case 136: -#line 895 "parse.y" +#line 901 "parse.y" { yyval.start = code_offset ; code1(_EXIT0) ; } break; case 137: -#line 898 "parse.y" +#line 904 "parse.y" { yyval.start = yystack.l_mark[-1].start ; code1(_EXIT) ; } break; case 138: -#line 902 "parse.y" +#line 908 "parse.y" { yyval.start = code_offset ; code1(_RET0) ; } break; case 139: -#line 905 "parse.y" +#line 911 "parse.y" { yyval.start = yystack.l_mark[-1].start ; code1(_RET) ; } break; case 140: -#line 911 "parse.y" +#line 917 "parse.y" { yyval.start = code_offset ; code2(F_PUSHA, &field[0]) ; code1(_PUSHINT) ; code1(0) ; @@ -2421,7 +2428,7 @@ case 140: } break; case 141: -#line 918 "parse.y" +#line 924 "parse.y" { yyval.start = yystack.l_mark[0].start ; code1(_PUSHINT) ; code1(0) ; code2(_BUILTIN, bi_getline) ; @@ -2429,42 +2436,42 @@ case 141: } break; case 142: -#line 924 "parse.y" +#line 930 "parse.y" { code1(_PUSHINT) ; code1(F_IN) ; code2(_BUILTIN, bi_getline) ; /* getline_flag already off in yylex() */ } break; case 143: -#line 929 "parse.y" +#line 935 "parse.y" { code2(F_PUSHA, &field[0]) ; code1(_PUSHINT) ; code1(PIPE_IN) ; code2(_BUILTIN, bi_getline) ; } break; case 144: -#line 934 "parse.y" +#line 940 "parse.y" { code1(_PUSHINT) ; code1(PIPE_IN) ; code2(_BUILTIN, bi_getline) ; } break; case 145: -#line 940 "parse.y" +#line 946 "parse.y" { getline_flag = 1 ; } break; case 148: -#line 945 "parse.y" +#line 951 "parse.y" { yyval.start = code_offset ; code2(F_PUSHA, field+0) ; } break; case 149: -#line 949 "parse.y" +#line 955 "parse.y" { yyval.start = yystack.l_mark[-1].start ; } break; case 150: -#line 957 "parse.y" +#line 963 "parse.y" { INST *p5 = CDP(yystack.l_mark[-1].start) ; INST *p6 = CDP(yystack.l_mark[0].start) ; @@ -2477,31 +2484,32 @@ case 150: cast_to_REPL(cp) ; p5->op = _PUSHC ; p5[1].ptr = (PTR) cp ; + no_leaks_cell(cp); } code2(_BUILTIN, yystack.l_mark[-5].fp) ; yyval.start = yystack.l_mark[-3].start ; } break; case 151: -#line 975 "parse.y" +#line 982 "parse.y" { yyval.fp = bi_sub ; } break; case 152: -#line 976 "parse.y" +#line 983 "parse.y" { yyval.fp = bi_gsub ; } break; case 153: -#line 981 "parse.y" +#line 988 "parse.y" { yyval.start = code_offset ; code2(F_PUSHA, &field[0]) ; } break; case 154: -#line 986 "parse.y" +#line 993 "parse.y" { yyval.start = yystack.l_mark[-1].start ; } break; case 155: -#line 994 "parse.y" +#line 1001 "parse.y" { resize_fblock(yystack.l_mark[-1].fbp) ; restore_ids() ; @@ -2509,7 +2517,7 @@ case 155: } break; case 156: -#line 1003 "parse.y" +#line 1010 "parse.y" { eat_nl() ; scope = SCOPE_FUNCT ; active_funct = yystack.l_mark[-3].fbp ; @@ -2528,7 +2536,7 @@ case 156: } break; case 157: -#line 1022 "parse.y" +#line 1029 "parse.y" { FBLOCK *fbp ; if ( yystack.l_mark[0].stp->type == ST_NONE ) @@ -2552,18 +2560,18 @@ case 157: } break; case 158: -#line 1045 "parse.y" +#line 1052 "parse.y" { yyval.fbp = yystack.l_mark[0].fbp ; if ( yystack.l_mark[0].fbp->code ) compile_error("redefinition of %s" , yystack.l_mark[0].fbp->name) ; } break; case 159: -#line 1051 "parse.y" +#line 1058 "parse.y" { yyval.ival = 0 ; } break; case 161: -#line 1056 "parse.y" +#line 1063 "parse.y" { yystack.l_mark[0].stp = save_id(yystack.l_mark[0].stp->name) ; yystack.l_mark[0].stp->type = ST_LOCAL_NONE ; yystack.l_mark[0].stp->offset = 0 ; @@ -2571,7 +2579,7 @@ case 161: } break; case 162: -#line 1062 "parse.y" +#line 1069 "parse.y" { if ( is_local(yystack.l_mark[0].stp) ) compile_error("%s is duplicated in argument list", yystack.l_mark[0].stp->name) ; @@ -2584,7 +2592,7 @@ case 162: } break; case 163: -#line 1075 "parse.y" +#line 1082 "parse.y" { /* we may have to recover from a bungled function definition */ /* can have local ids, before code scope @@ -2595,7 +2603,7 @@ case 163: } break; case 164: -#line 1088 "parse.y" +#line 1095 "parse.y" { yyval.start = yystack.l_mark[-1].start ; code2(_CALL, yystack.l_mark[-2].fbp) ; @@ -2606,22 +2614,22 @@ case 164: } break; case 165: -#line 1099 "parse.y" +#line 1106 "parse.y" { yyval.ca_p = (CA_REC *) 0 ; } break; case 166: -#line 1101 "parse.y" +#line 1108 "parse.y" { yyval.ca_p = yystack.l_mark[0].ca_p ; yyval.ca_p->link = yystack.l_mark[-1].ca_p ; yyval.ca_p->arg_num = (short) (yystack.l_mark[-1].ca_p ? yystack.l_mark[-1].ca_p->arg_num+1 : 0) ; } break; case 167: -#line 1116 "parse.y" +#line 1123 "parse.y" { yyval.ca_p = (CA_REC *) 0 ; } break; case 168: -#line 1118 "parse.y" +#line 1125 "parse.y" { yyval.ca_p = ZMALLOC(CA_REC) ; yyval.ca_p->link = yystack.l_mark[-2].ca_p ; yyval.ca_p->type = CA_EXPR ; @@ -2630,7 +2638,7 @@ case 168: } break; case 169: -#line 1125 "parse.y" +#line 1132 "parse.y" { yyval.ca_p = ZMALLOC(CA_REC) ; yyval.ca_p->type = ST_NONE ; yyval.ca_p->link = yystack.l_mark[-2].ca_p ; @@ -2640,20 +2648,20 @@ case 169: } break; case 170: -#line 1135 "parse.y" +#line 1142 "parse.y" { yyval.ca_p = ZMALLOC(CA_REC) ; yyval.ca_p->type = CA_EXPR ; yyval.ca_p->call_offset = code_offset ; } break; case 171: -#line 1141 "parse.y" +#line 1148 "parse.y" { yyval.ca_p = ZMALLOC(CA_REC) ; yyval.ca_p->type = ST_NONE ; code_call_id(yyval.ca_p, yystack.l_mark[-1].stp) ; } break; -#line 2656 "y.tab.c" +#line 2664 "y.tab.c" } yystack.s_mark -= yym; yystate = *yystack.s_mark; diff --git a/parse.y b/parse.y index 4c975a4..3e13b80 100644 --- a/parse.y +++ b/parse.y @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: parse.y,v 1.11 2010/08/02 08:56:20 tom Exp $ + * $MawkId: parse.y,v 1.13 2010/08/13 00:00:56 tom Exp $ * @Log: parse.y,v @ * Revision 1.11 1995/06/11 22:40:09 mike * change if(dump_code) -> if(dump_code_flag) @@ -344,6 +344,7 @@ expr : cat_expr cp->type = C_STRING ; cp->ptr = p3[1].ptr ; cast_to_RE(cp) ; + no_leaks_re_ptr(cp->ptr) ; code_ptr -= 2 ; code2(_MATCH1, cp->ptr) ; ZFREE(cp) ; @@ -398,7 +399,10 @@ p_expr : DOUBLE ; p_expr : RE - { $$ = code_offset ; code2(_MATCH0, $1) ; } + { $$ = code_offset ; + code2(_MATCH0, $1) ; + no_leaks_re_ptr($1); + } ; p_expr : p_expr PLUS p_expr { code1(_ADD) ; } @@ -852,6 +856,7 @@ split_back : RPAREN cast_for_split(cp) ; code_ptr[-2].op = _PUSHC ; code_ptr[-1].ptr = (PTR) cp ; + no_leaks_cell(cp); } } } @@ -884,6 +889,7 @@ re_arg : expr cast_to_RE(cp) ; p1->op = _PUSHC ; p1[1].ptr = (PTR) cp ; + no_leaks_cell(cp); } } } @@ -966,6 +972,7 @@ p_expr : sub_or_gsub LPAREN re_arg COMMA expr sub_back cast_to_REPL(cp) ; p5->op = _PUSHC ; p5[1].ptr = (PTR) cp ; + no_leaks_cell(cp); } code2(_BUILTIN, $1) ; $$ = $3 ; @@ -1339,6 +1346,7 @@ static void RE_as_arg(void) cp->type = C_RE ; cp->ptr = code_ptr[1].ptr ; code2(_PUSHC, cp) ; + no_leaks_cell_ptr(cp); } /* reset the active_code back to the MAIN block */ diff --git a/patchlev.h b/patchlev.h index d10f550..e8afe9d 100644 --- a/patchlev.h +++ b/patchlev.h @@ -1,7 +1,7 @@ /* - * $MawkId: patchlev.h,v 1.29 2010/07/18 09:24:03 tom Exp $ + * $MawkId: patchlev.h,v 1.30 2010/08/18 23:44:02 tom Exp $ */ #define PATCH_BASE 1 #define PATCH_LEVEL 3 #define PATCH_STRING ".4" -#define DATE_STRING "20100718" +#define DATE_STRING "20100818" diff --git a/re_cmpl.c b/re_cmpl.c index 47a02d7..9e74bdc 100644 --- a/re_cmpl.c +++ b/re_cmpl.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: re_cmpl.c,v 1.16 2010/08/04 09:17:25 tom Exp $ + * $MawkId: re_cmpl.c,v 1.21 2010/08/18 18:00:53 tom Exp $ * @Log: re_cmpl.c,v @ * Revision 1.6 1994/12/13 00:14:58 mike * \\ -> \ on second replacement scan @@ -95,6 +95,8 @@ re_compile(STRING * sval) sval->ref_cnt++; p->re.anchored = (*s == '^'); if (!(p->re.compiled = REcompile(s, sval->len))) { + ZFREE(p); + sval->ref_cnt--; if (mawk_state == EXECUTION) rt_error(efmt, REerror(), s); else { /* compiling */ @@ -112,7 +114,7 @@ re_compile(STRING * sval) #ifdef DEBUG if (dump_RE) - REmprint(refRE_DATA(p->re), stderr); + REmprint(p->re.compiled, stderr); #endif return refRE_DATA(p->re); } @@ -142,10 +144,10 @@ re_destroy(PTR m) RE_NODE *r; if (p != 0) { - free_STRING(p->sval); - REdestroy(p->re.compiled); for (q = re_list, r = 0; q != 0; r = q, q = q->link) { if (q == p) { + free_STRING(p->sval); + REdestroy(p->re.compiled); if (r != 0) r->link = q->link; else @@ -419,3 +421,44 @@ replv_to_repl(CELL * cp, STRING * sval) zfree(sblock, vcnt * sizeof(STRING *)); return cp; } + +#ifdef NO_LEAKS +typedef struct _all_ptrs { + struct _all_ptrs *next; + PTR m; +} ALL_PTRS; + +static ALL_PTRS *all_ptrs; +/* + * Some regular expressions are parsed, and the pointer stored in the byte-code + * where we cannot distinguish it from other constants. Keep a list here, to + * free on exit for auditing. + */ +void +no_leaks_re_ptr(PTR m) +{ + ALL_PTRS *p = calloc(1, sizeof(ALL_PTRS)); + p->next = all_ptrs; + p->m = m; + all_ptrs = p; +} + +void +re_leaks(void) +{ + while (all_ptrs != 0) { + ALL_PTRS *next = all_ptrs->next; + re_destroy(all_ptrs->m); + free(all_ptrs); + all_ptrs = next; + } + + while (repl_list != 0) { + REPL_NODE *p = repl_list->link; + free_STRING(repl_list->sval); + free_cell_data(repl_list->cp); + ZFREE(repl_list); + repl_list = p; + } +} +#endif diff --git a/regexp.c b/regexp.c index 1de6874..eb9b6a8 100644 --- a/regexp.c +++ b/regexp.c @@ -1,4 +1,4 @@ -/* $MawkId: regexp.c,v 1.4 2010/07/31 00:15:13 tom Exp $ */ +/* $MawkId: regexp.c,v 1.6 2010/08/13 22:50:06 tom Exp $ */ #ifdef LOCAL_REGEXP # include "mawk.h" # include "rexp.c" @@ -17,7 +17,9 @@ void rexp_leaks(void) { + TRACE(("rexp_leaks\n")); #ifdef LOCAL_REGEXP + lookup_cclass(0); if (bv_base) { BV **p = bv_base; while (p != bv_next) { diff --git a/rexp.c b/rexp.c index abd9571..514e173 100644 --- a/rexp.c +++ b/rexp.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: rexp.c,v 1.14 2010/08/04 00:23:35 tom Exp $ + * $MawkId: rexp.c,v 1.15 2010/08/13 00:15:43 tom Exp $ * @Log: rexp.c,v @ * Revision 1.3 1996/09/02 18:47:36 mike * Make ^* and ^+ syntax errors. @@ -248,7 +248,7 @@ void RE_panic(const char *s) { fprintf(stderr, "REcompile() - panic: %s\n", s); - exit(100); + mawk_exit(100); } /* getting regexp error message */ diff --git a/rexp0.c b/rexp0.c index 6a7aa0d..ea4c96c 100644 --- a/rexp0.c +++ b/rexp0.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: rexp0.c,v 1.25 2010/07/31 00:15:35 tom Exp $ + * $MawkId: rexp0.c,v 1.26 2010/08/13 22:53:06 tom Exp $ * @Log: rexp0.c,v @ * Revision 1.5 1996/11/08 15:39:27 mike * While cleaning up block_on, I introduced a bug. Now fixed. @@ -413,6 +413,18 @@ lookup_cclass(char **start) size_t size; size_t item; +#ifdef NO_LEAKS + if (start == 0) { + for (item = 0; item < sizeof(cclass_table) / + sizeof(cclass_table[0]); ++item) { + if (cclass_table[item].data) { + free(cclass_table[item].data); + cclass_table[item].data = 0; + } + } + return 0; + } +#endif name = (*start += 2); /* point past "[:" */ colon = strchr(name, ':'); if (colon == 0 || colon[1] != ']') diff --git a/rexp2.c b/rexp2.c index cd0eea0..1ab087c 100644 --- a/rexp2.c +++ b/rexp2.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: rexp2.c,v 1.19 2010/07/21 23:05:59 tom Exp $ + * $MawkId: rexp2.c,v 1.20 2010/08/13 00:15:16 tom Exp $ * @Log: rexp2.c,v @ * Revision 1.3 1993/07/24 17:55:12 mike * more cleanup @@ -128,7 +128,7 @@ RE_new_run_stack(void) /* this is pretty unusual, I've only seen it happen on weird input to REmatch() under 16bit DOS , the same situation worked easily on 32bit machine. */ - exit(100); + mawk_exit(100); } RE_run_stack_limit = RE_run_stack_base + newsize; @@ -152,7 +152,7 @@ RE_new_pos_stack(void) if (!RE_pos_stack_base) { fprintf(stderr, "out of memory for RE string position stack\n"); - exit(100); + mawk_exit(100); } RE_pos_stack_limit = RE_pos_stack_base + newsize; diff --git a/rexpdb.c b/rexpdb.c index 948e6d0..c86976b 100644 --- a/rexpdb.c +++ b/rexpdb.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: rexpdb.c,v 1.9 2010/05/07 22:09:39 tom Exp $ + * $MawkId: rexpdb.c,v 1.10 2010/08/18 17:59:30 tom Exp $ * @Log: rexpdb.c,v @ * Revision 1.2 1993/07/23 13:21:51 mike * cleanup rexp code @@ -60,11 +60,11 @@ REmprint(PTR m, FILE *f) end_on_string = ""; if (p->s_type < 0 || p->s_type >= END_ON) { - fprintf(f, "unknown STATE type\n"); + fprintf(f, "unknown STATE type %d\n", (int) (p->s_type)); return; } - fprintf(f, "%-10s", xlat[(UChar) (p->s_type)]); + fprintf(f, "%-10s", xlat[((UChar) (p->s_type)) % U_ON]); switch (p->s_type) { case M_STR: da_string(f, p->s_data.str, (size_t) p->s_len); @@ -81,7 +81,7 @@ REmprint(PTR m, FILE *f) UChar *q = (UChar *) p->s_data.bvp; UChar *r = q + sizeof(BV); while (q < r) - fprintf(f, "%x ", *q++); + fprintf(f, "%2x ", *q++); } break; } diff --git a/symtype.h b/symtype.h index f955969..c5aab46 100644 --- a/symtype.h +++ b/symtype.h @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: symtype.h,v 1.11 2010/08/02 09:16:19 tom Exp $ + * $MawkId: symtype.h,v 1.12 2010/08/13 09:55:03 tom Exp $ * @Log: symtype.h,v @ * Revision 1.6 1996/02/01 04:39:43 mike * dynamic array scheme @@ -128,6 +128,9 @@ typedef struct { const char *name; char type; unsigned char offset; /* offset in stack frame for local vars */ +#ifdef NO_LEAKS + char free_name; +#endif union { CELL *cp; int kw; diff --git a/zmalloc.c b/zmalloc.c index 05f499c..f51bb8c 100644 --- a/zmalloc.c +++ b/zmalloc.c @@ -10,7 +10,7 @@ the GNU General Public License, version 2, 1991. ********************************************/ /* - * $MawkId: zmalloc.c,v 1.21 2010/07/30 09:23:48 tom Exp $ + * $MawkId: zmalloc.c,v 1.23 2010/08/18 23:16:40 tom Exp $ * @Log: zmalloc.c,v @ * Revision 1.6 1995/06/06 00:18:35 mike * change mawk_exit(1) to mawk_exit(2) @@ -92,9 +92,13 @@ the GNU General Public License, version 2, 1991. * Define DEBUG_ZMALLOC to build mawk with a simpler interface to the system * malloc, which verifies whether the size-parameter passed to zfree() is * consistent with the zmalloc() parameter. + * + * The NO_LEAKS code relies upon this simpler interface. */ -/* #define DEBUG_ZMALLOC 1 */ +#if !defined(DEBUG_ZMALLOC) && defined(NO_LEAKS) +#define DEBUG_ZMALLOC 1 +#endif #ifdef DEBUG_ZMALLOC #define IsPoolable(blocks) ((blocks) == 0) @@ -137,7 +141,7 @@ show_ptr_data(void) static void free_ptr_data(void *a) { - TRACE(("free_ptr_data %p\n", a)); + TRACE(("free_ptr_data %p -> %p\n", a, ((PTR_DATA *) (a))->ptr)); free(a); } @@ -184,7 +188,9 @@ static void finish_ptr(PTR ptr, size_t size) { PTR_DATA dummy; + PTR_DATA *later; PTR_DATA **item; + void *check; dummy.ptr = ptr; dummy.size = size; @@ -200,7 +206,12 @@ finish_ptr(PTR ptr, size_t size) (*item)->ptr, (unsigned long) (*item)->size)); - tdelete(item, &ptr_data, compare_ptr_data); + later = *item; + check = tdelete(&dummy, &ptr_data, compare_ptr_data); + if (check) { + free(later); + } + ShowPtrData(); }