Browse Source

fix memory leaks in ASRC and in INPgetTree()

implement a reference counter `usecnt' for the elements
  of the `INPparseTree'
rlar 14 years ago
parent
commit
58b0614467
  1. 1
      src/include/ngspice/inpdefs.h
  2. 1
      src/include/ngspice/inpptree.h
  3. 3
      src/spicelib/devices/asrc/asrcdest.c
  4. 256
      src/spicelib/parser/inpptree.c

1
src/include/ngspice/inpdefs.h

@ -104,6 +104,7 @@ char *INPgetModBin(CKTcircuit *, char *, INPmodel **, INPtables *, char *);
int INPgetTok(char **, char **, int); int INPgetTok(char **, char **, int);
int INPgetNetTok(char **, char **, int); int INPgetNetTok(char **, char **, int);
void INPgetTree(char **, INPparseTree **, CKTcircuit *, INPtables *); void INPgetTree(char **, INPparseTree **, CKTcircuit *, INPtables *);
void INPfreeTree(IFparseTree *);
IFvalue *INPgetValue(CKTcircuit *, char **, int, INPtables *); IFvalue *INPgetValue(CKTcircuit *, char **, int, INPtables *);
int INPgndInsert(CKTcircuit *, char **, INPtables *, CKTnode **); int INPgndInsert(CKTcircuit *, char **, INPtables *, CKTnode **);
int INPinsertNofree(char **token, INPtables *tab); int INPinsertNofree(char **token, INPtables *tab);

1
src/include/ngspice/inpptree.h

@ -52,6 +52,7 @@ typedef struct INPparseNode {
int funcnum; /* ... one of PTF_*, */ int funcnum; /* ... one of PTF_*, */
void (*function)(void); /* ... and pointer to the function. */ void (*function)(void); /* ... and pointer to the function. */
void *data; /* private data for certain functions, currently PTF_PWL */ void *data; /* private data for certain functions, currently PTF_PWL */
int usecnt;
} INPparseNode; } INPparseNode;

3
src/spicelib/devices/asrc/asrcdest.c

@ -21,6 +21,9 @@ ASRCdestroy(GENmodel **model)
for(here = mod->ASRCinstances ; here ; here = next) { for(here = mod->ASRCinstances ; here ; here = next) {
next = here->ASRCnextInstance; next = here->ASRCnextInstance;
FREE(here->ASRCacValues); FREE(here->ASRCacValues);
INPfreeTree(here->ASRCtree);
if(here->ASRCposptr)
free(here->ASRCposptr);
FREE(here); FREE(here);
} }
nextmod = mod->ASRCnextModel; nextmod = mod->ASRCnextModel;

256
src/spicelib/parser/inpptree.c

@ -26,6 +26,74 @@ static INPparseNode *mknnode(double number);
static INPparseNode *mksnode(const char *string, void *ckt); static INPparseNode *mksnode(const char *string, void *ckt);
static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum); 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" #include "inpptree-parser.c"
static IFvalue *values = NULL; static IFvalue *values = NULL;
@ -140,9 +208,10 @@ INPgetTree(char **line, INPparseTree ** pt, CKTcircuit *ckt, INPtables * tab)
rv = PTparse(line, &p, ckt); rv = PTparse(line, &p, ckt);
if (rv || !PTcheck(p)) {
if (rv || !p || !PTcheck(p)) {
*pt = NULL; *pt = NULL;
release_tree(p);
} else { } else {
@ -152,12 +221,12 @@ INPgetTree(char **line, INPparseTree ** pt, CKTcircuit *ckt, INPtables * tab)
(*pt)->p.varTypes = types; (*pt)->p.varTypes = types;
(*pt)->p.vars = values; (*pt)->p.vars = values;
(*pt)->p.IFeval = IFeval; (*pt)->p.IFeval = IFeval;
(*pt)->tree = p;
(*pt)->tree = inc_usage(p);
(*pt)->derivs = TMALLOC(INPparseNode *, numvalues); (*pt)->derivs = TMALLOC(INPparseNode *, numvalues);
for (i = 0; i < numvalues; i++) 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) static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum)
{ {
INPparseNode *arg1 = NULL, *arg2, *newp;
INPparseNode *arg1 = NULL, *arg2 = NULL, *newp = NULL;
switch (p->type) { switch (p->type) {
case PT_TIME: case PT_TIME:
@ -278,7 +347,7 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum)
// printTree(newp); // printTree(newp);
// printf("\n"); // printf("\n");
return (newp);
return mkfirst(newp, p);
} }
case PT_FUNCTION: case PT_FUNCTION:
@ -474,7 +543,7 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum)
printTree(newp); printTree(newp);
printf("\n"); printf("\n");
#endif #endif
return (newp);
return mkfirst(newp, p);
} }
break; break;
@ -513,14 +582,13 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum)
mkb(PT_DIVIDE, arg1, p->left->left)), mkb(PT_DIVIDE, arg1, p->left->left)),
mkb(PT_TIMES, arg2, mkf(PTF_LN, p->left->left)))); mkb(PT_TIMES, arg2, mkf(PTF_LN, p->left->left))));
} }
return (newp);
return mkfirst(newp, p);
} }
default: default:
fprintf(stderr, "Internal Error: bad function # %d\n", fprintf(stderr, "Internal Error: bad function # %d\n",
p->funcnum); p->funcnum);
newp = NULL;
break;
return mkfirst(NULL, p);
} }
arg2 = PTdifferentiate(p->left, varnum); arg2 = PTdifferentiate(p->left, varnum);
@ -535,7 +603,7 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum)
break; break;
} }
return (newp);
return mkfirst(newp, p);
} }
static INPparseNode *mkcon(double value) static INPparseNode *mkcon(double value)
@ -544,6 +612,7 @@ static INPparseNode *mkcon(double value)
p->type = PT_CONSTANT; p->type = PT_CONSTANT;
p->constant = value; p->constant = value;
p->usecnt = 0;
return (p); return (p);
} }
@ -555,81 +624,91 @@ static INPparseNode *mkb(int type, INPparseNode * left,
int i; int i;
if ((right->type == PT_CONSTANT) && (left->type == PT_CONSTANT)) { if ((right->type == PT_CONSTANT) && (left->type == PT_CONSTANT)) {
double value;
switch (type) { switch (type) {
case PT_TIMES: case PT_TIMES:
return (mkcon(left->constant * right->constant));
value = left->constant * right->constant;
return mkfirst(mkcon(value), mkfirst(left, right));
case PT_DIVIDE: case PT_DIVIDE:
return (mkcon(left->constant / right->constant));
value = left->constant / right->constant;
return mkfirst(mkcon(value), mkfirst(left, right));
case PT_PLUS: case PT_PLUS:
return (mkcon(left->constant + right->constant));
value = left->constant + right->constant;
return mkfirst(mkcon(value), mkfirst(left, right));
case PT_MINUS: case PT_MINUS:
return (mkcon(left->constant - right->constant));
value = left->constant - right->constant;
return mkfirst(mkcon(value), mkfirst(left, right));
case PT_POWER: 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) { switch (type) {
case PT_TIMES: case PT_TIMES:
if ((left->type == PT_CONSTANT) && (left->constant == 0)) if ((left->type == PT_CONSTANT) && (left->constant == 0))
return (left);
return mkfirst(left, right);
else if ((right->type == PT_CONSTANT) && (right->constant == 0)) else if ((right->type == PT_CONSTANT) && (right->constant == 0))
return (right);
return mkfirst(right, left);
else if ((left->type == PT_CONSTANT) && (left->constant == 1)) else if ((left->type == PT_CONSTANT) && (left->constant == 1))
return (right);
return mkfirst(right, left);
else if ((right->type == PT_CONSTANT) && (right->constant == 1)) else if ((right->type == PT_CONSTANT) && (right->constant == 1))
return (left);
return mkfirst(left, right);
break; break;
case PT_DIVIDE: case PT_DIVIDE:
if ((left->type == PT_CONSTANT) && (left->constant == 0)) if ((left->type == PT_CONSTANT) && (left->constant == 0))
return (left);
return mkfirst(left, right);
else if ((right->type == PT_CONSTANT) && (right->constant == 1)) else if ((right->type == PT_CONSTANT) && (right->constant == 1))
return (left);
return mkfirst(left, right);
break; break;
case PT_PLUS: case PT_PLUS:
if ((left->type == PT_CONSTANT) && (left->constant == 0)) if ((left->type == PT_CONSTANT) && (left->constant == 0))
return (right);
return mkfirst(right, left);
else if ((right->type == PT_CONSTANT) && (right->constant == 0)) else if ((right->type == PT_CONSTANT) && (right->constant == 0))
return (left);
return mkfirst(left, right);
break; break;
case PT_MINUS: case PT_MINUS:
if ((right->type == PT_CONSTANT) && (right->constant == 0)) if ((right->type == PT_CONSTANT) && (right->constant == 0))
return (left);
return mkfirst(left, right);
else if ((left->type == PT_CONSTANT) && (left->constant == 0)) else if ((left->type == PT_CONSTANT) && (left->constant == 0))
return (mkf(PTF_UMINUS, right));
return mkfirst(mkf(PTF_UMINUS, right), left);
break; break;
case PT_POWER: case PT_POWER:
if (right->type == PT_CONSTANT) { if (right->type == PT_CONSTANT) {
if (right->constant == 0) if (right->constant == 0)
return (mkcon(1.0));
return mkfirst(mkcon(1.0), mkfirst(left, right));
else if (right->constant == 1) else if (right->constant == 1)
return (left);
return mkfirst(left, right);
} }
break; break;
case PT_TERN: case PT_TERN:
if (left->type == PT_CONSTANT)
if (left->type == PT_CONSTANT) {
/*FIXME > 0.0, >= 0.5, != 0.0 or what ? */ /*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) && if((right->left->type == PT_CONSTANT) &&
(right->right->type == PT_CONSTANT) && (right->right->type == PT_CONSTANT) &&
(right->left->constant == right->right->constant)) (right->left->constant == right->right->constant))
return (right->left);
return mkfirst(right->left, mkfirst(right, left));
break; break;
} }
p = TMALLOC(INPparseNode, 1); p = TMALLOC(INPparseNode, 1);
p->type = type; 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) { if(type == PT_TERN) {
p->function = NULL; p->function = NULL;
@ -666,13 +745,15 @@ static INPparseNode *mkf(int type, INPparseNode * arg)
if (arg->type == PT_CONSTANT) { if (arg->type == PT_CONSTANT) {
double constval = PTunary(funcs[i].funcptr) (arg->constant); double constval = PTunary(funcs[i].funcptr) (arg->constant);
return (mkcon(constval));
return mkfirst(mkcon(constval), arg);
} }
p = TMALLOC(INPparseNode, 1); p = TMALLOC(INPparseNode, 1);
p->type = PT_FUNCTION; p->type = PT_FUNCTION;
p->left = arg;
p->usecnt = 0;
p->left = inc_usage(arg);
p->funcnum = i; p->funcnum = i;
p->function = funcs[i].funcptr; p->function = funcs[i].funcptr;
@ -731,16 +812,18 @@ static INPparseNode *mkbnode(const char *opstr, INPparseNode * arg1,
if (i == NUM_OPS) { if (i == NUM_OPS) {
fprintf(stderr, "Internal Error: no such op num %s\n", opstr); fprintf(stderr, "Internal Error: no such op num %s\n", opstr);
return (NULL);
return mkfirst(NULL, mkfirst(arg1, arg2));
} }
p = TMALLOC(INPparseNode, 1); p = TMALLOC(INPparseNode, 1);
p->type = ops[i].number; p->type = ops[i].number;
p->usecnt = 0;
p->funcname = ops[i].name; p->funcname = ops[i].name;
p->function = ops[i].funcptr; p->function = ops[i].funcptr;
p->left = arg1;
p->right = arg2;
p->left = inc_usage(arg1);
p->right = inc_usage(arg2);
return (p); return (p);
} }
@ -786,7 +869,7 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p)
if (i<2 || (i%1)) { if (i<2 || (i%1)) {
fprintf(stderr, "Error: PWL(expr, points...) needs an even and >=2 number of constant args\n"); 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); data = TMALLOC(struct pwldata, 1);
@ -794,6 +877,8 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p)
data->n = i; data->n = i;
p->data = (void *) data;
for (w = p->left ; --i >= 0 ; w = w->left) for (w = p->left ; --i >= 0 ; w = w->left)
if (w->right->type == PT_CONSTANT) { if (w->right->type == PT_CONSTANT) {
data->vals[i] = w->right->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); fprintf(stderr, " type = %d\n", w->right->type);
//Breakpoint; //Breakpoint;
fprintf(stderr, "Error: PWL(expr, points...) only *literal* points are supported\n"); fprintf(stderr, "Error: PWL(expr, points...) only *literal* points are supported\n");
return (NULL);
return mkfirst(NULL, p);
} }
#ifdef TRACE #ifdef TRACE
@ -817,15 +902,16 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p)
for (i = 2 ; i < data->n ; i += 2) for (i = 2 ; i < data->n ; i += 2)
if(data->vals[i-2] >= data->vals[i]) { if(data->vals[i-2] >= data->vals[i]) {
fprintf(stderr, "Error: PWL(expr, points...) the abscissa of points must be ascending\n"); 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, /* strip all but the first arg,
* and attach the rest as opaque data to the INPparseNode * and attach the rest as opaque data to the INPparseNode
*/ */
w = inc_usage(w);
dec_usage(p->left);
p->left = w; p->left = w;
p->data = (void *) data;
return (p); return (p);
} }
@ -852,14 +938,16 @@ static INPparseNode *mkfnode(const char *fname, INPparseNode * arg)
p = TMALLOC(INPparseNode, 1); p = TMALLOC(INPparseNode, 1);
p->type = PT_TERN; 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"); fprintf(stderr, "Error: bogus ternary_fcn form\n");
return (NULL);
return mkfirst(NULL, arg);
} }
for (i = 0; i < NUM_FUNCS; i++) for (i = 0; i < NUM_FUNCS; i++)
@ -868,13 +956,15 @@ static INPparseNode *mkfnode(const char *fname, INPparseNode * arg)
if (i == NUM_FUNCS) { if (i == NUM_FUNCS) {
fprintf(stderr, "Error: no such function '%s'\n", buf); fprintf(stderr, "Error: no such function '%s'\n", buf);
return (NULL);
return mkfirst(NULL, arg);
} }
p = TMALLOC(INPparseNode, 1); p = TMALLOC(INPparseNode, 1);
p->type = PT_FUNCTION; p->type = PT_FUNCTION;
p->left = arg;
p->usecnt = 0;
p->left = inc_usage(arg);
p->funcname = funcs[i].name; p->funcname = funcs[i].name;
p->funcnum = funcs[i].number; p->funcnum = funcs[i].number;
p->function = funcs[i].funcptr; p->function = funcs[i].funcptr;
@ -911,6 +1001,7 @@ static INPparseNode *mkvnode(char *name)
} }
p->valueIndex = i; p->valueIndex = i;
p->type = PT_VAR; p->type = PT_VAR;
p->usecnt = 0;
return (p); return (p);
} }
@ -939,6 +1030,7 @@ static INPparseNode *mkinode(char *name)
} }
p->valueIndex = i; p->valueIndex = i;
p->type = PT_VAR; p->type = PT_VAR;
p->usecnt = 0;
return (p); return (p);
} }
@ -952,6 +1044,8 @@ static INPparseNode *mknnode(double number)
p = TMALLOC(INPparseNode, 1); p = TMALLOC(INPparseNode, 1);
p->type = PT_CONSTANT; p->type = PT_CONSTANT;
p->usecnt = 0;
p->constant = number; p->constant = number;
return (p); return (p);
@ -971,6 +1065,8 @@ static INPparseNode *mksnode(const char *string, void *ckt)
p = TMALLOC(INPparseNode, 1); p = TMALLOC(INPparseNode, 1);
p->usecnt = 0;
if(!strcmp("time", buf)) { if(!strcmp("time", buf)) {
p->type = PT_TIME; p->type = PT_TIME;
p->data = ckt; p->data = ckt;
@ -1221,6 +1317,72 @@ int PTlex (YYSTYPE *lvalp, struct PTltype *llocp, char **line)
return (token); 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 #ifdef TRACE
/* Debugging stuff. */ /* Debugging stuff. */

Loading…
Cancel
Save