]> granicus.if.org Git - postgresql/commitdiff
Fix memory leak in repeated SPGIST index scans.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 31 Oct 2018 21:04:42 +0000 (17:04 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 31 Oct 2018 21:05:03 +0000 (17:05 -0400)
spgendscan neglected to pfree all the memory allocated by spgbeginscan.
It's possible to get away with that in most normal queries, since the
memory is allocated in the executor's per-query context which is about
to get deleted anyway; but it causes severe memory leakage during
creation or filling of large exclusion-constraint indexes.

Also, document that amendscan is supposed to free what ambeginscan
allocates.  The docs' lack of clarity on that point probably caused this
bug to begin with.  (There is discussion of changing that API spec going
forward, but I don't think it'd be appropriate for the back branches.)

Per report from Bruno Wolff.  It's been like this since the beginning,
so back-patch to all active branches.

In HEAD, also fix an independent leak caused by commit 2a6368343
(allocating memory during spgrescan instead of spgbeginscan, which
might be all right if it got cleaned up, but it didn't).  And do a bit
of code beautification on that commit, too.

Discussion: https://postgr.es/m/20181024012314.GA27428@wolff.to

doc/src/sgml/indexam.sgml
src/backend/access/spgist/spgscan.c

index beb99d1831ab58ea1e1b03f669363ae97f3f17bd..d758a4987dc66af647b04a4837d17d2f48b1884b 100644 (file)
@@ -614,7 +614,8 @@ amendscan (IndexScanDesc scan);
 </programlisting>
    End a scan and release resources.  The <literal>scan</literal> struct itself
    should not be freed, but any locks or pins taken internally by the
-   access method must be released.
+   access method must be released, as well as any other memory allocated
+   by <function>ambeginscan</function> and other scan-related functions.
   </para>
 
   <para>
index a63fde2c8af8184475c5355fea40ac499ce7a356..c883ae95e48c0e9f61b0cc552170cf781da90662 100644 (file)
@@ -294,10 +294,18 @@ spgbeginscan(Relation rel, int keysz, int orderbysz)
        /* Set up indexTupDesc and xs_hitupdesc in case it's an index-only scan */
        so->indexTupDesc = scan->xs_hitupdesc = RelationGetDescr(rel);
 
+       /* Allocate various arrays needed for order-by scans */
        if (scan->numberOfOrderBys > 0)
        {
-               so->zeroDistances = palloc(sizeof(double) * scan->numberOfOrderBys);
-               so->infDistances = palloc(sizeof(double) * scan->numberOfOrderBys);
+               /* This will be filled in spgrescan, but allocate the space here */
+               so->orderByTypes = (Oid *)
+                       palloc(sizeof(Oid) * scan->numberOfOrderBys);
+
+               /* These arrays have constant contents, so we can fill them now */
+               so->zeroDistances = (double *)
+                       palloc(sizeof(double) * scan->numberOfOrderBys);
+               so->infDistances = (double *)
+                       palloc(sizeof(double) * scan->numberOfOrderBys);
 
                for (i = 0; i < scan->numberOfOrderBys; i++)
                {
@@ -305,9 +313,12 @@ spgbeginscan(Relation rel, int keysz, int orderbysz)
                        so->infDistances[i] = get_float8_infinity();
                }
 
-               scan->xs_orderbyvals = palloc0(sizeof(Datum) * scan->numberOfOrderBys);
-               scan->xs_orderbynulls = palloc(sizeof(bool) * scan->numberOfOrderBys);
-               memset(scan->xs_orderbynulls, true, sizeof(bool) * scan->numberOfOrderBys);
+               scan->xs_orderbyvals = (Datum *)
+                       palloc0(sizeof(Datum) * scan->numberOfOrderBys);
+               scan->xs_orderbynulls = (bool *)
+                       palloc(sizeof(bool) * scan->numberOfOrderBys);
+               memset(scan->xs_orderbynulls, true,
+                          sizeof(bool) * scan->numberOfOrderBys);
        }
 
        fmgr_info_copy(&so->innerConsistentFn,
@@ -336,6 +347,7 @@ spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
                memmove(scan->keyData, scankey,
                                scan->numberOfKeys * sizeof(ScanKeyData));
 
+       /* initialize order-by data if needed */
        if (orderbys && scan->numberOfOrderBys > 0)
        {
                int                     i;
@@ -343,8 +355,6 @@ spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
                memmove(scan->orderByData, orderbys,
                                scan->numberOfOrderBys * sizeof(ScanKeyData));
 
-               so->orderByTypes = (Oid *) palloc(sizeof(Oid) * scan->numberOfOrderBys);
-
                for (i = 0; i < scan->numberOfOrderBys; i++)
                {
                        ScanKey         skey = &scan->orderByData[i];
@@ -380,11 +390,22 @@ spgendscan(IndexScanDesc scan)
        MemoryContextDelete(so->tempCxt);
        MemoryContextDelete(so->traversalCxt);
 
+       if (so->keyData)
+               pfree(so->keyData);
+
+       if (so->state.deadTupleStorage)
+               pfree(so->state.deadTupleStorage);
+
        if (scan->numberOfOrderBys > 0)
        {
+               pfree(so->orderByTypes);
                pfree(so->zeroDistances);
                pfree(so->infDistances);
+               pfree(scan->xs_orderbyvals);
+               pfree(scan->xs_orderbynulls);
        }
+
+       pfree(so);
 }
 
 /*