Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix unsafe memory management in CloneRowTriggersToPartition().
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 3 Jun 2019 20:59:16 +0000 (16:59 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 3 Jun 2019 20:59:26 +0000 (16:59 -0400)
It's not really supported to call systable_getnext() in a different
memory context than systable_beginscan() was called in, and it's
*definitely* not safe to do so and then reset that context between
calls.  I'm not very clear on how this code survived
CLOBBER_CACHE_ALWAYS testing ... but Alexander Lakhin found a case
that would crash it pretty reliably.

Per bug #15828.  Fix, and backpatch to v11 where this code came in.

Discussion: https://postgr.es/m/15828-f6ddd7df4852f473@postgresql.org

src/backend/commands/tablecmds.c

index e34d4ccc148071ef66e68a36eded7c110f02960d..95af5ec2dc709e05297eb2832d5f4e65dcc7255b 100644 (file)
@@ -15772,8 +15772,7 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
    ScanKeyData key;
    SysScanDesc scan;
    HeapTuple   tuple;
-   MemoryContext oldcxt,
-               perTupCxt;
+   MemoryContext perTupCxt;
 
    ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
                F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
@@ -15783,18 +15782,16 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
 
    perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
                                      "clone trig", ALLOCSET_SMALL_SIZES);
-   oldcxt = MemoryContextSwitchTo(perTupCxt);
 
    while (HeapTupleIsValid(tuple = systable_getnext(scan)))
    {
-       Form_pg_trigger trigForm;
+       Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
        CreateTrigStmt *trigStmt;
        Node       *qual = NULL;
        Datum       value;
        bool        isnull;
        List       *cols = NIL;
-
-       trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
+       MemoryContext oldcxt;
 
        /*
         * Ignore statement-level triggers; those are not cloned.
@@ -15813,6 +15810,9 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
            elog(ERROR, "unexpected trigger \"%s\" found",
                 NameStr(trigForm->tgname));
 
+       /* Use short-lived context for CREATE TRIGGER */
+       oldcxt = MemoryContextSwitchTo(perTupCxt);
+
        /*
         * If there is a WHEN clause, generate a 'cooked' version of it that's
         * appropriate for the partition.
@@ -15876,10 +15876,10 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
                      trigForm->tgfoid, trigForm->oid, qual,
                      false, true);
 
+       MemoryContextSwitchTo(oldcxt);
        MemoryContextReset(perTupCxt);
    }
 
-   MemoryContextSwitchTo(oldcxt);
    MemoryContextDelete(perTupCxt);
 
    systable_endscan(scan);