To suppress memory leakage in long-lived Lists, lremove() should pfree

the cons cell it's deleting from the list.  Do this, and fix a few callers
that were bogusly assuming it wouldn't free the cons cell.
This commit is contained in:
Tom Lane 2002-12-17 01:18:35 +00:00
parent 9f76d0d926
commit e932a724a4
6 changed files with 51 additions and 32 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.42 2002/11/24 21:52:13 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.43 2002/12/17 01:18:18 tgl Exp $
* *
* NOTES * NOTES
* XXX a few of the following functions are duplicated to handle * XXX a few of the following functions are duplicated to handle
@ -269,7 +269,6 @@ llasti(List *l)
* Free the List nodes of a list * Free the List nodes of a list
* The pointed-to nodes, if any, are NOT freed. * The pointed-to nodes, if any, are NOT freed.
* This works for integer lists too. * This works for integer lists too.
*
*/ */
void void
freeList(List *list) freeList(List *list)
@ -487,6 +486,7 @@ lremove(void *elem, List *list)
result = lnext(l); result = lnext(l);
else else
lnext(prev) = lnext(l); lnext(prev) = lnext(l);
pfree(l);
} }
return result; return result;
} }
@ -518,6 +518,7 @@ LispRemove(void *elem, List *list)
result = lnext(l); result = lnext(l);
else else
lnext(prev) = lnext(l); lnext(prev) = lnext(l);
pfree(l);
} }
return result; return result;
} }
@ -545,6 +546,7 @@ lremovei(int elem, List *list)
result = lnext(l); result = lnext(l);
else else
lnext(prev) = lnext(l); lnext(prev) = lnext(l);
pfree(l);
} }
return result; return result;
} }

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.42 2002/12/12 15:49:32 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.43 2002/12/17 01:18:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -101,12 +101,17 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
*/ */
newset = NIL; newset = NIL;
foreach(cursetlink, root->equi_key_list) /* cannot use foreach here because of possible lremove */
cursetlink = root->equi_key_list;
while (cursetlink)
{ {
List *curset = lfirst(cursetlink); List *curset = lfirst(cursetlink);
bool item1here = member(item1, curset); bool item1here = member(item1, curset);
bool item2here = member(item2, curset); bool item2here = member(item2, curset);
/* must advance cursetlink before lremove possibly pfree's it */
cursetlink = lnext(cursetlink);
if (item1here || item2here) if (item1here || item2here)
{ {
/* /*
@ -128,9 +133,7 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
newset = set_union(newset, curset); newset = set_union(newset, curset);
/* /*
* Remove old set from equi_key_list. NOTE this does not * Remove old set from equi_key_list.
* change lnext(cursetlink), so the foreach loop doesn't
* break.
*/ */
root->equi_key_list = lremove(curset, root->equi_key_list); root->equi_key_list = lremove(curset, root->equi_key_list);
freeList(curset); /* might as well recycle old cons cells */ freeList(curset); /* might as well recycle old cons cells */

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.78 2002/12/12 15:49:32 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.79 2002/12/17 01:18:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -910,13 +910,18 @@ qual_is_redundant(Query *root,
do do
{ {
someadded = false; someadded = false;
foreach(olditem, oldquals) /* cannot use foreach here because of possible lremove */
olditem = oldquals;
while (olditem)
{ {
RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem); RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
Node *oldleft = (Node *) get_leftop(oldrinfo->clause); Node *oldleft = (Node *) get_leftop(oldrinfo->clause);
Node *oldright = (Node *) get_rightop(oldrinfo->clause); Node *oldright = (Node *) get_rightop(oldrinfo->clause);
Node *newguy = NULL; Node *newguy = NULL;
/* must advance olditem before lremove possibly pfree's it */
olditem = lnext(olditem);
if (member(oldleft, equalvars)) if (member(oldleft, equalvars))
newguy = oldright; newguy = oldright;
else if (member(oldright, equalvars)) else if (member(oldright, equalvars))
@ -930,8 +935,6 @@ qual_is_redundant(Query *root,
/* /*
* Remove this qual from list, since we don't need it anymore. * Remove this qual from list, since we don't need it anymore.
* Note this doesn't break the foreach() loop, since lremove
* doesn't touch the next-link of the removed cons cell.
*/ */
oldquals = lremove(oldrinfo, oldquals); oldquals = lremove(oldrinfo, oldquals);
} }

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.257 2002/12/13 19:45:56 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.258 2002/12/17 01:18:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -521,32 +521,38 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
* Prepare columns for assignment to target table. * Prepare columns for assignment to target table.
*/ */
attnos = attrnos; attnos = attrnos;
foreach(tl, qry->targetList) /* cannot use foreach here because of possible lremove */
tl = qry->targetList;
while (tl)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(tl); TargetEntry *tle = (TargetEntry *) lfirst(tl);
ResTarget *col; ResTarget *col;
/* must advance tl before lremove possibly pfree's it */
tl = lnext(tl);
if (icolumns == NIL || attnos == NIL) if (icolumns == NIL || attnos == NIL)
elog(ERROR, "INSERT has more expressions than target columns"); elog(ERROR, "INSERT has more expressions than target columns");
col = (ResTarget *) lfirst(icolumns); col = (ResTarget *) lfirst(icolumns);
Assert(IsA(col, ResTarget));
/* /*
* When the value is to be set to the column default we can simply * When the value is to be set to the column default we can simply
* drop it now and handle it later on using methods for missing * drop the TLE now and handle it later on using methods for missing
* columns. * columns.
*/ */
if (!IsA(tle, InsertDefault)) if (IsA(tle, InsertDefault))
{ {
Assert(IsA(col, ResTarget)); qry->targetList = lremove(tle, qry->targetList);
Assert(!tle->resdom->resjunk); /* Note: the stmt->cols list is not adjusted to match */
updateTargetListEntry(pstate, tle, col->name, lfirsti(attnos),
col->indirection);
} }
else else
{ {
icolumns = lremove(icolumns, icolumns); /* Normal case */
attnos = lremove(attnos, attnos); Assert(!tle->resdom->resjunk);
qry->targetList = lremove(tle, qry->targetList); updateTargetListEntry(pstate, tle, col->name, lfirsti(attnos),
col->indirection);
} }
icolumns = lnext(icolumns); icolumns = lnext(icolumns);
@ -554,8 +560,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
} }
/* /*
* Ensure that the targetlist has the same number of entries that * Ensure that the targetlist has the same number of entries that
* were present in the columns list. Don't do the check for select * were present in the columns list. Don't do the check unless
* an explicit columns list was given, though.
* statements. * statements.
*/ */
if (stmt->cols != NIL && (icolumns != NIL || attnos != NIL)) if (stmt->cols != NIL && (icolumns != NIL || attnos != NIL))

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.114 2002/12/12 15:49:40 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.115 2002/12/17 01:18:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -205,9 +205,11 @@ adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
{ {
RangeTblRef *rtr = lfirst(jjt); RangeTblRef *rtr = lfirst(jjt);
if (IsA(rtr, RangeTblRef) &&rtr->rtindex == rt_index) if (IsA(rtr, RangeTblRef) &&
rtr->rtindex == rt_index)
{ {
newjointree = lremove(rtr, newjointree); newjointree = lremove(rtr, newjointree);
/* foreach is safe because we exit loop after lremove... */
break; break;
} }
} }

View File

@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.123 2002/12/12 15:49:40 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.124 2002/12/17 01:18:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1953,10 +1953,15 @@ estimate_num_groups(Query *root, List *groupClauses, double input_rows)
if (HeapTupleIsValid(statsTuple)) if (HeapTupleIsValid(statsTuple))
ReleaseSysCache(statsTuple); ReleaseSysCache(statsTuple);
foreach(l2, varinfos) /* cannot use foreach here because of possible lremove */
l2 = varinfos;
while (l2)
{ {
MyVarInfo *varinfo = (MyVarInfo *) lfirst(l2); MyVarInfo *varinfo = (MyVarInfo *) lfirst(l2);
/* must advance l2 before lremove possibly pfree's it */
l2 = lnext(l2);
if (var->varno != varinfo->var->varno && if (var->varno != varinfo->var->varno &&
vars_known_equal(root, var, varinfo->var)) vars_known_equal(root, var, varinfo->var))
{ {
@ -1969,10 +1974,7 @@ estimate_num_groups(Query *root, List *groupClauses, double input_rows)
} }
else else
{ {
/* /* Delete the older item */
* Delete the older item. We assume lremove() will not
* break the lnext link of the item...
*/
varinfos = lremove(varinfo, varinfos); varinfos = lremove(varinfo, varinfos);
} }
} }