From: Tom Lane Date: Mon, 3 Jun 2019 20:59:16 +0000 (-0400) Subject: Fix unsafe memory management in CloneRowTriggersToPartition(). X-Git-Tag: REL_11_4~32 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=601084eb1aa8f1ae5303d9cf130d5b8cc385b517;p=postgresql Fix unsafe memory management in CloneRowTriggersToPartition(). 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 --- diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3cd899b1f9..96e85bd6ce 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -15082,8 +15082,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))); @@ -15093,18 +15092,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. @@ -15123,6 +15120,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. @@ -15186,10 +15186,10 @@ CloneRowTriggersToPartition(Relation parent, Relation partition) trigForm->tgfoid, HeapTupleGetOid(tuple), qual, false, true); + MemoryContextSwitchTo(oldcxt); MemoryContextReset(perTupCxt); } - MemoryContextSwitchTo(oldcxt); MemoryContextDelete(perTupCxt); systable_endscan(scan);