From 58b0614467d3de5895419a83be4e99de4ef63385 Mon Sep 17 00:00:00 2001 From: rlar Date: Sat, 7 Apr 2012 19:16:39 +0200 Subject: [PATCH] fix memory leaks in ASRC and in INPgetTree() implement a reference counter `usecnt' for the elements of the `INPparseTree' --- src/include/ngspice/inpdefs.h | 1 + src/include/ngspice/inpptree.h | 1 + src/spicelib/devices/asrc/asrcdest.c | 3 + src/spicelib/parser/inpptree.c | 256 ++++++++++++++++++++++----- 4 files changed, 214 insertions(+), 47 deletions(-) diff --git a/src/include/ngspice/inpdefs.h b/src/include/ngspice/inpdefs.h index 443c43be4..265ad416b 100644 --- a/src/include/ngspice/inpdefs.h +++ b/src/include/ngspice/inpdefs.h @@ -104,6 +104,7 @@ char *INPgetModBin(CKTcircuit *, char *, INPmodel **, INPtables *, char *); int INPgetTok(char **, char **, int); int INPgetNetTok(char **, char **, int); void INPgetTree(char **, INPparseTree **, CKTcircuit *, INPtables *); +void INPfreeTree(IFparseTree *); IFvalue *INPgetValue(CKTcircuit *, char **, int, INPtables *); int INPgndInsert(CKTcircuit *, char **, INPtables *, CKTnode **); int INPinsertNofree(char **token, INPtables *tab); diff --git a/src/include/ngspice/inpptree.h b/src/include/ngspice/inpptree.h index f4a26880f..68aa08c08 100644 --- a/src/include/ngspice/inpptree.h +++ b/src/include/ngspice/inpptree.h @@ -52,6 +52,7 @@ typedef struct INPparseNode { int funcnum; /* ... one of PTF_*, */ void (*function)(void); /* ... and pointer to the function. */ void *data; /* private data for certain functions, currently PTF_PWL */ + int usecnt; } INPparseNode; diff --git a/src/spicelib/devices/asrc/asrcdest.c b/src/spicelib/devices/asrc/asrcdest.c index d96036d12..26f08ffad 100644 --- a/src/spicelib/devices/asrc/asrcdest.c +++ b/src/spicelib/devices/asrc/asrcdest.c @@ -21,6 +21,9 @@ ASRCdestroy(GENmodel **model) for(here = mod->ASRCinstances ; here ; here = next) { next = here->ASRCnextInstance; FREE(here->ASRCacValues); + INPfreeTree(here->ASRCtree); + if(here->ASRCposptr) + free(here->ASRCposptr); FREE(here); } nextmod = mod->ASRCnextModel; diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index f257210cd..9c5ef0781 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -26,6 +26,74 @@ static INPparseNode *mknnode(double number); static INPparseNode *mksnode(const char *string, void *ckt); static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum); +static void free_tree(INPparseNode *); + + +/* + * LAW for INPparseNode* generator and consumer functions: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Newly allocated structs shall be initialized with `usecnt' = 0 + * When filling INPparseNode * slots of newly initialized structs + * their `usecnt' shall be incremented + * Generators pass the responsibility `to free' return values + * on to their invokers. + * Functions generally process args with exactly one of: + * - inc_usage(arg) if they insert an argument into a struct + * - release_tree(arg) if they don't make any use of it + * - pass it on to another function() + * Functions use the the result of a function invocations with one of: + * - inc_usage(result) if they insert the result into a struct + * - release_tree(result) if they don't make any use of it + * - pass it on to another function() + * - simply return the result + * + * mkfirst(first, second) + * is used to safely release its second argument, + * and return its first + * + */ + + +static inline INPparseNode * +inc_usage(INPparseNode *p) +{ + if(p) + p->usecnt ++; + return p; +} + + +static void +dec_usage(INPparseNode *p) +{ + if(p && --p->usecnt <= 0) + free_tree(p); +} + + +static void +release_tree(INPparseNode *p) +{ + if(p && p->usecnt <= 0) + free_tree(p); +} + + +static INPparseNode * +mkfirst(INPparseNode *fst, INPparseNode *snd) +{ + if(fst) { + fst->usecnt ++; + release_tree(snd); + fst->usecnt --; + } else { + release_tree(snd); + } + + return fst; +} + + #include "inpptree-parser.c" static IFvalue *values = NULL; @@ -140,9 +208,10 @@ INPgetTree(char **line, INPparseTree ** pt, CKTcircuit *ckt, INPtables * tab) rv = PTparse(line, &p, ckt); - if (rv || !PTcheck(p)) { + if (rv || !p || !PTcheck(p)) { *pt = NULL; + release_tree(p); } else { @@ -152,12 +221,12 @@ INPgetTree(char **line, INPparseTree ** pt, CKTcircuit *ckt, INPtables * tab) (*pt)->p.varTypes = types; (*pt)->p.vars = values; (*pt)->p.IFeval = IFeval; - (*pt)->tree = p; + (*pt)->tree = inc_usage(p); (*pt)->derivs = TMALLOC(INPparseNode *, numvalues); for (i = 0; i < numvalues; i++) - (*pt)->derivs[i] = PTdifferentiate(p, i); + (*pt)->derivs[i] = inc_usage(PTdifferentiate(p, i)); } @@ -180,7 +249,7 @@ INPgetTree(char **line, INPparseTree ** pt, CKTcircuit *ckt, INPtables * tab) static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) { - INPparseNode *arg1 = NULL, *arg2, *newp; + INPparseNode *arg1 = NULL, *arg2 = NULL, *newp = NULL; switch (p->type) { case PT_TIME: @@ -278,7 +347,7 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) // printTree(newp); // printf("\n"); - return (newp); + return mkfirst(newp, p); } case PT_FUNCTION: @@ -474,7 +543,7 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) printTree(newp); printf("\n"); #endif - return (newp); + return mkfirst(newp, p); } break; @@ -513,14 +582,13 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) mkb(PT_DIVIDE, arg1, p->left->left)), mkb(PT_TIMES, arg2, mkf(PTF_LN, p->left->left)))); } - return (newp); + return mkfirst(newp, p); } default: fprintf(stderr, "Internal Error: bad function # %d\n", p->funcnum); - newp = NULL; - break; + return mkfirst(NULL, p); } arg2 = PTdifferentiate(p->left, varnum); @@ -535,7 +603,7 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) break; } - return (newp); + return mkfirst(newp, p); } static INPparseNode *mkcon(double value) @@ -544,6 +612,7 @@ static INPparseNode *mkcon(double value) p->type = PT_CONSTANT; p->constant = value; + p->usecnt = 0; return (p); } @@ -555,81 +624,91 @@ static INPparseNode *mkb(int type, INPparseNode * left, int i; if ((right->type == PT_CONSTANT) && (left->type == PT_CONSTANT)) { + double value; switch (type) { case PT_TIMES: - return (mkcon(left->constant * right->constant)); + value = left->constant * right->constant; + return mkfirst(mkcon(value), mkfirst(left, right)); case PT_DIVIDE: - return (mkcon(left->constant / right->constant)); + value = left->constant / right->constant; + return mkfirst(mkcon(value), mkfirst(left, right)); case PT_PLUS: - return (mkcon(left->constant + right->constant)); + value = left->constant + right->constant; + return mkfirst(mkcon(value), mkfirst(left, right)); case PT_MINUS: - return (mkcon(left->constant - right->constant)); + value = left->constant - right->constant; + return mkfirst(mkcon(value), mkfirst(left, right)); case PT_POWER: - return (mkcon(pow(left->constant, right->constant))); + value = pow(left->constant, right->constant); + return mkfirst(mkcon(value), mkfirst(left, right)); } } switch (type) { case PT_TIMES: if ((left->type == PT_CONSTANT) && (left->constant == 0)) - return (left); + return mkfirst(left, right); else if ((right->type == PT_CONSTANT) && (right->constant == 0)) - return (right); + return mkfirst(right, left); else if ((left->type == PT_CONSTANT) && (left->constant == 1)) - return (right); + return mkfirst(right, left); else if ((right->type == PT_CONSTANT) && (right->constant == 1)) - return (left); + return mkfirst(left, right); break; case PT_DIVIDE: if ((left->type == PT_CONSTANT) && (left->constant == 0)) - return (left); + return mkfirst(left, right); else if ((right->type == PT_CONSTANT) && (right->constant == 1)) - return (left); + return mkfirst(left, right); break; case PT_PLUS: if ((left->type == PT_CONSTANT) && (left->constant == 0)) - return (right); + return mkfirst(right, left); else if ((right->type == PT_CONSTANT) && (right->constant == 0)) - return (left); + return mkfirst(left, right); break; case PT_MINUS: if ((right->type == PT_CONSTANT) && (right->constant == 0)) - return (left); + return mkfirst(left, right); else if ((left->type == PT_CONSTANT) && (left->constant == 0)) - return (mkf(PTF_UMINUS, right)); + return mkfirst(mkf(PTF_UMINUS, right), left); break; case PT_POWER: if (right->type == PT_CONSTANT) { if (right->constant == 0) - return (mkcon(1.0)); + return mkfirst(mkcon(1.0), mkfirst(left, right)); else if (right->constant == 1) - return (left); + return mkfirst(left, right); } break; case PT_TERN: - if (left->type == PT_CONSTANT) + if (left->type == PT_CONSTANT) { /*FIXME > 0.0, >= 0.5, != 0.0 or what ? */ - return ((left->constant != 0.0) ? right->left : right->right); + p = (left->constant != 0.0) ? right->left : right->right; + return mkfirst(p, mkfirst(right, left)); + } if((right->left->type == PT_CONSTANT) && (right->right->type == PT_CONSTANT) && (right->left->constant == right->right->constant)) - return (right->left); + return mkfirst(right->left, mkfirst(right, left)); break; } p = TMALLOC(INPparseNode, 1); p->type = type; - p->left = left; - p->right = right; + p->usecnt = 0; + + p->left = inc_usage(left); + p->right = inc_usage(right); if(type == PT_TERN) { p->function = NULL; @@ -666,13 +745,15 @@ static INPparseNode *mkf(int type, INPparseNode * arg) if (arg->type == PT_CONSTANT) { double constval = PTunary(funcs[i].funcptr) (arg->constant); - return (mkcon(constval)); + return mkfirst(mkcon(constval), arg); } p = TMALLOC(INPparseNode, 1); p->type = PT_FUNCTION; - p->left = arg; + p->usecnt = 0; + + p->left = inc_usage(arg); p->funcnum = i; p->function = funcs[i].funcptr; @@ -731,16 +812,18 @@ static INPparseNode *mkbnode(const char *opstr, INPparseNode * arg1, if (i == NUM_OPS) { fprintf(stderr, "Internal Error: no such op num %s\n", opstr); - return (NULL); + return mkfirst(NULL, mkfirst(arg1, arg2)); } p = TMALLOC(INPparseNode, 1); p->type = ops[i].number; + p->usecnt = 0; + p->funcname = ops[i].name; p->function = ops[i].funcptr; - p->left = arg1; - p->right = arg2; + p->left = inc_usage(arg1); + p->right = inc_usage(arg2); return (p); } @@ -786,7 +869,7 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p) if (i<2 || (i%1)) { fprintf(stderr, "Error: PWL(expr, points...) needs an even and >=2 number of constant args\n"); - return (NULL); + return mkfirst(NULL, p); } data = TMALLOC(struct pwldata, 1); @@ -794,6 +877,8 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p) data->n = i; + p->data = (void *) data; + for (w = p->left ; --i >= 0 ; w = w->left) if (w->right->type == PT_CONSTANT) { data->vals[i] = w->right->constant; @@ -806,7 +891,7 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p) fprintf(stderr, " type = %d\n", w->right->type); //Breakpoint; fprintf(stderr, "Error: PWL(expr, points...) only *literal* points are supported\n"); - return (NULL); + return mkfirst(NULL, p); } #ifdef TRACE @@ -817,15 +902,16 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p) for (i = 2 ; i < data->n ; i += 2) if(data->vals[i-2] >= data->vals[i]) { fprintf(stderr, "Error: PWL(expr, points...) the abscissa of points must be ascending\n"); - return (NULL); + return mkfirst(NULL, p); } /* strip all but the first arg, * and attach the rest as opaque data to the INPparseNode */ + w = inc_usage(w); + dec_usage(p->left); p->left = w; - p->data = (void *) data; return (p); } @@ -852,14 +938,16 @@ static INPparseNode *mkfnode(const char *fname, INPparseNode * arg) p = TMALLOC(INPparseNode, 1); p->type = PT_TERN; - p->left = arg1; - p->right = mkb(PT_COMMA, arg2, arg3); + p->usecnt = 0; - return (p); + p->left = inc_usage(arg1); + p->right = inc_usage(mkb(PT_COMMA, arg2, arg3)); + + return mkfirst(p, arg); } fprintf(stderr, "Error: bogus ternary_fcn form\n"); - return (NULL); + return mkfirst(NULL, arg); } for (i = 0; i < NUM_FUNCS; i++) @@ -868,13 +956,15 @@ static INPparseNode *mkfnode(const char *fname, INPparseNode * arg) if (i == NUM_FUNCS) { fprintf(stderr, "Error: no such function '%s'\n", buf); - return (NULL); + return mkfirst(NULL, arg); } p = TMALLOC(INPparseNode, 1); p->type = PT_FUNCTION; - p->left = arg; + p->usecnt = 0; + + p->left = inc_usage(arg); p->funcname = funcs[i].name; p->funcnum = funcs[i].number; p->function = funcs[i].funcptr; @@ -911,6 +1001,7 @@ static INPparseNode *mkvnode(char *name) } p->valueIndex = i; p->type = PT_VAR; + p->usecnt = 0; return (p); } @@ -939,6 +1030,7 @@ static INPparseNode *mkinode(char *name) } p->valueIndex = i; p->type = PT_VAR; + p->usecnt = 0; return (p); } @@ -952,6 +1044,8 @@ static INPparseNode *mknnode(double number) p = TMALLOC(INPparseNode, 1); p->type = PT_CONSTANT; + p->usecnt = 0; + p->constant = number; return (p); @@ -971,6 +1065,8 @@ static INPparseNode *mksnode(const char *string, void *ckt) p = TMALLOC(INPparseNode, 1); + p->usecnt = 0; + if(!strcmp("time", buf)) { p->type = PT_TIME; p->data = ckt; @@ -1221,6 +1317,72 @@ int PTlex (YYSTYPE *lvalp, struct PTltype *llocp, char **line) return (token); } + +void INPfreeTree(IFparseTree *ptree) +{ + INPparseTree *pt = (INPparseTree *) ptree; + + int i; + + for (i = 0; i < pt->p.numVars; i++) + dec_usage(pt->derivs[i]); + + dec_usage(pt->tree); + + txfree(pt->derivs); + txfree(pt->p.varTypes); + txfree(pt->p.vars); + txfree(pt); +} + + +void free_tree(INPparseNode *pt) +{ + if(!pt) + return; + + if(pt->usecnt) { + fprintf(stderr, "ERROR: fatal internal error, %s\n", __func__); + exit(1); + } + + switch (pt->type) { + case PT_TIME: + case PT_TEMPERATURE: + case PT_FREQUENCY: + case PT_CONSTANT: + case PT_VAR: + break; + + case PT_PLUS: + case PT_MINUS: + case PT_TIMES: + case PT_DIVIDE: + case PT_POWER: + case PT_COMMA: + case PT_TERN: + dec_usage(pt->right); + case PT_FUNCTION: + dec_usage(pt->left); + break; + + default: + printf("oops"); + break; + } + + if(pt->type == PT_FUNCTION && pt->funcnum == PTF_PWL) { + struct pwldata { int n; double *vals; } *data = (struct pwldata*)(pt->data); + if(data) { + txfree(data->vals); + txfree(data); + } + } + + txfree(pt); +} + + #ifdef TRACE /* Debugging stuff. */