mirror of
https://github.com/postgres/postgres.git
synced 2025-06-23 14:01:44 +03:00
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:
@ -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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user