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
This commit is contained in:
Tom Lane 2019-06-03 16:59:16 -04:00
parent 3c461d510d
commit 601084eb1a
1 changed files with 7 additions and 7 deletions

View File

@ -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);