Commit eaf0292c authored by Tom Lane's avatar Tom Lane

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
parent 05d36b68
...@@ -15772,8 +15772,7 @@ CloneRowTriggersToPartition(Relation parent, Relation partition) ...@@ -15772,8 +15772,7 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
ScanKeyData key; ScanKeyData key;
SysScanDesc scan; SysScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
MemoryContext oldcxt, MemoryContext perTupCxt;
perTupCxt;
ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, ScanKeyInit(&key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber,
F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent))); F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(parent)));
...@@ -15783,18 +15782,16 @@ CloneRowTriggersToPartition(Relation parent, Relation partition) ...@@ -15783,18 +15782,16 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
perTupCxt = AllocSetContextCreate(CurrentMemoryContext, perTupCxt = AllocSetContextCreate(CurrentMemoryContext,
"clone trig", ALLOCSET_SMALL_SIZES); "clone trig", ALLOCSET_SMALL_SIZES);
oldcxt = MemoryContextSwitchTo(perTupCxt);
while (HeapTupleIsValid(tuple = systable_getnext(scan))) while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{ {
Form_pg_trigger trigForm; Form_pg_trigger trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
CreateTrigStmt *trigStmt; CreateTrigStmt *trigStmt;
Node *qual = NULL; Node *qual = NULL;
Datum value; Datum value;
bool isnull; bool isnull;
List *cols = NIL; List *cols = NIL;
MemoryContext oldcxt;
trigForm = (Form_pg_trigger) GETSTRUCT(tuple);
/* /*
* Ignore statement-level triggers; those are not cloned. * Ignore statement-level triggers; those are not cloned.
...@@ -15813,6 +15810,9 @@ CloneRowTriggersToPartition(Relation parent, Relation partition) ...@@ -15813,6 +15810,9 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
elog(ERROR, "unexpected trigger \"%s\" found", elog(ERROR, "unexpected trigger \"%s\" found",
NameStr(trigForm->tgname)); 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 * If there is a WHEN clause, generate a 'cooked' version of it that's
* appropriate for the partition. * appropriate for the partition.
...@@ -15876,10 +15876,10 @@ CloneRowTriggersToPartition(Relation parent, Relation partition) ...@@ -15876,10 +15876,10 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
trigForm->tgfoid, trigForm->oid, qual, trigForm->tgfoid, trigForm->oid, qual,
false, true); false, true);
MemoryContextSwitchTo(oldcxt);
MemoryContextReset(perTupCxt); MemoryContextReset(perTupCxt);
} }
MemoryContextSwitchTo(oldcxt);
MemoryContextDelete(perTupCxt); MemoryContextDelete(perTupCxt);
systable_endscan(scan); systable_endscan(scan);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment