fix memory leaks in ASRC and in INPgetTree()

implement a reference counter `usecnt' for the elements
  of the `INPparseTree'
This commit is contained in:
rlar 2012-04-07 19:16:39 +02:00
parent 4fb75fbd51
commit 58b0614467
4 changed files with 214 additions and 47 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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. */