From eaf0292c3ba7acac2735f99a8988bd49a26112f5 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 3 Jun 2019 16:59:16 -0400 Subject: [PATCH] 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 --- src/backend/commands/tablecmds.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index e34d4ccc14..95af5ec2dc 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -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); -- 2.40.0