fix memory leaks in ASRC and in INPgetTree()
implement a reference counter `usecnt' for the elements of the `INPparseTree'
This commit is contained in:
parent
4fb75fbd51
commit
58b0614467
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue