[CHECKER] 4 memory leaks in Postgresql 7.4.2

From: Ted Kremenek <kremenek(at)cs(dot)stanford(dot)edu>
To: pgsql-bugs(at)postgresql(dot)org
Cc: Ted Kremenek <mc(at)cs(dot)stanford(dot)edu>
Subject: [CHECKER] 4 memory leaks in Postgresql 7.4.2
Date: 2004-04-30 09:48:41
Message-ID: 8FF4B9A8-9A8B-11D8-A836-000393B3CE92@cs.stanford.edu
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Hi,

I'm from the Stanford Metacompilation research group where we use
static analysis to find bugs. I'm trying a new technique, so I would
appreciate feedback on these error reports.

This technique tries to infer API roles automatically from the code.
In particular, I am trying to check for ownership properties of
functions (i.e., which functions return ownership of a pointer, which
ones claim it, etc.). This allows us to potentially find memory leaks
that we didn't check for before because we didn't know what functions
allocated memory or acquired resources.

The tool is still in the early stages, so the bugs reported may be
false positives. I have applied it to Postgresql 7.4.2. Included
below are 4 error reports that I believe to be memory leaks.

Any feedback would be appreciated.

Best,
Ted Kremenek

------------------------------------------------------------------------
------------------------------------------

[BUG] memory leak of vacrelstats at end of function laxy_vaccum_rel()
File where bug occurred:
postgresql-7.4.2/src/backend/commands/vacuumlazy.c

Diagnosis:

(1) palloc0 returns memory at line 141 and address is stored in
vacrelstats
(2) vaccrelstats goes out of scope at the end of the function;
leaking the memory

131 BlockNumber possibly_freeable;
132
133 if (vacstmt->verbose)
134 elevel = INFO;
135 else
136 elevel = DEBUG2;
137
138 vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
139 &OldestXmin, &FreezeLimit);
140

---> vacrelstats is allocated

141 vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
142
143 /* Set threshold for interesting free space = average request size
*/
144 /* XXX should we scale it up or down? Adjust vacuum.c too, if so
*/
145 vacrelstats->threshold = GetAvgFSMRequestSize(&onerel->rd_node);
146
147 /* Open all indexes of the relation */
148 vac_open_indexes(onerel, &nindexes, &Irel);
149 hasindex = (nindexes > 0);
150
151 /* Do the vacuuming */
152 lazy_scan_heap(onerel, vacrelstats, Irel, nindexes);
153
154 /* Done with indexes */
155 vac_close_indexes(nindexes, Irel);
156
157 /*
158 * Optionally truncate the relation.
159 *
160 * Don't even think about it unless we have a shot at releasing a
goodly
161 * number of pages. Otherwise, the time taken isn't worth it.
162 */
163 possibly_freeable = vacrelstats->rel_pages -
vacrelstats->nonempty_pages;
164 if (possibly_freeable >= REL_TRUNCATE_MINIMUM ||
165 possibly_freeable >= vacrelstats->rel_pages /
REL_TRUNCATE_FRACTION)
166 lazy_truncate_heap(onerel, vacrelstats);
167
168 /* Update shared free space map with final free space info */
169 lazy_update_fsm(onerel, vacrelstats);
170
171 /* Update statistics in pg_class */
172 vac_update_relstats(RelationGetRelid(onerel),
vacrelstats->rel_pages,
173 vacrelstats->rel_tuples, hasindex);

--> goes out of scope

174 }

------------------------------------------------------------------------
------------------------------------------

[BUG] memory leak on error path (dtype != DTK_DELTA)
File where bug occurred:
postgresql-7.4.2/src/interfaces/ecpg/pgtypeslib/interval.c

Diagnosis:

(1) memory is allocated on line 778 by calling pgtypes_alloc; stored
in result
(2) leaked on error path on line 785

File where bug occurred:
/home/kremenek/oses_src/postgresql-7.4.2/src/interfaces/ecpg/
pgtypeslib/interval.c

768 return NULL;
769 }
770
771 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf,
ptr) != 0)
772 || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
773 {
774 errno = PGTYPES_INTVL_BAD_INTERVAL;
775 return NULL;
776 }
777

---> memory is allocated

778 result = (interval *) pgtypes_alloc(sizeof(interval));
779 if (!result)
780 return NULL;
781
782 if (dtype != DTK_DELTA)
783 {
784 errno = PGTYPES_INTVL_BAD_INTERVAL;
785 return NULL;

---> memory is leaked on error path

786 }
787
788 if (tm2interval(tm, fsec, result) != 0)

------------------------------------------------------------------------
------------------------------------------

[BUG] difficult to analyze, but it appears that subquery is memory
leaked
File where bug occurred:
postgresql-7.4.2/src/backend/optimizer/plan/subselect.c

Diagnosis:

(1) copyObject() appears to return newly allocated memory on line 261
(2) subquery is passed to subquery_planner on line 296, but within
that
function subquery itself never appears to be freed
(3) subquery has a field dereference on line 301, but afterwards
never
appears to be referenced
(4) pointer goes out of scope at end of function

This one I am less confident about, since it is difficult for me to
reason about the inter-procedural semantics.

File where bug occurred:
/home/kremenek/oses_src/postgresql-7.4.2/src/backend/optimizer/plan/
subselect.c

252 int paramid;
253 List *lst;
254 Node *result;
255
256 /*
257 * Copy the source Query node. This is a quick and dirty kluge to
258 * resolve the fact that the parser can generate trees with
multiple
259 * links to the same sub-Query node, but the planner wants to
scribble
260 * on the Query. Try to clean this up when we do querytree
redesign...
261 */
--->
262 subquery = (Query *) copyObject(subquery);
263
264 /*
265 * For an EXISTS subplan, tell lower-level planner to expect that
only
266 * the first tuple will be retrieved. For ALL and ANY subplans, we
267 * will be able to stop evaluating if the test condition fails, so
268 * very often not all the tuples will be retrieved; for lack of a
269 * better idea, specify 50% retrieval. For EXPR and MULTIEXPR
270 * subplans, use default behavior (we're only expecting one row
out,
271 * anyway).
272 *
273 * NOTE: if you change these numbers, also change
cost_qual_eval_walker()
274 * in path/costsize.c.
275 *
276 * XXX If an ALL/ANY subplan is uncorrelated, we may decide to
hash or
277 * materialize its result below. In that case it would've been
better
278 * to specify full retrieval. At present, however, we can only
detect
279 * correlation or lack of it after we've made the subplan :-(.
Perhaps
280 * detection of correlation should be done as a separate step.
281 * Meanwhile, we don't want to be too optimistic about the
percentage
282 * of tuples retrieved, for fear of selecting a plan that's bad for
283 * the materialization case.
284 */
285 if (slink->subLinkType == EXISTS_SUBLINK)
286 tuple_fraction = 1.0; /* just like a LIMIT 1 */
287 else if (slink->subLinkType == ALL_SUBLINK ||
288 slink->subLinkType == ANY_SUBLINK)
289 tuple_fraction = 0.5; /* 50% */
290 else
291 tuple_fraction = 0.0; /* default behavior */
292
293 /*
294 * Generate the plan for the subquery.
295 */
296 node->plan = plan = subquery_planner(subquery, tuple_fraction);
--->
297
298 node->plan_id = PlannerPlanId++; /* Assign unique ID to this
299 * SubPlan */
300
301 node->rtable = subquery->rtable;
302
303 /*
304 * Initialize other fields of the SubPlan node.
305 */
306 node->subLinkType = slink->subLinkType;

------------------------------------------------------------------------
------------------------------------------

[BUG] memory leak, pformats is allocated but never freed or stored
anywhere
File where bug occurred: postgresql-7.4.2/src/backend/tcop/postgres.c

Diagnosis:

(1) pformats is allocated on line 1261
(2) pformats is never stored anywhere, nor is it freed before going
out of scope

1251 MemoryContextSwitchTo(MessageContext);
1252
1253 /* Get the fixed part of the message */
1254 portal_name = pq_getmsgstring(input_message);
1255 stmt_name = pq_getmsgstring(input_message);
1256
1257 /* Get the parameter format codes */
1258 numPFormats = pq_getmsgint(input_message, 2);
1259 if (numPFormats > 0)
1260 {
--->
1261 pformats = (int16 *) palloc(numPFormats * sizeof(int16));
--->
1262 for (i = 0; i < numPFormats; i++)
1263 pformats[i] = pq_getmsgint(input_message, 2);
1264 }
1265
1266 /* Get the parameter value count */
1267 numParams = pq_getmsgint(input_message, 2);
1268
1269 if (numPFormats > 1 && numPFormats != numParams)
1270 ereport(ERROR,
1271 (errcode(ERRCODE_PROTOCOL_VIOLATION),

Browse pgsql-bugs by date

  From Date Subject
Next Message PostgreSQL Bugs List 2004-04-30 15:43:17 BUG #1145: silent REVOKE failures
Previous Message Arturs Zoldners 2004-04-30 09:36:07 Re: BUG #1142: Problem with update permissions for view