aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomas Vondra <tomas.vondra@postgresql.org>2023-07-02 20:29:01 +0200
committerTomas Vondra <tomas.vondra@postgresql.org>2023-07-02 22:23:20 +0200
commit984c23f6f5926f7cfb304b8f931e9bb66174b41c (patch)
tree3ea47f3139545e585a48f929f5eba66f8ccf9524 /src
parent3ce761d5cafeb0d63f2cb0e9876ba1578c1333c5 (diff)
downloadpostgresql-984c23f6f5926f7cfb304b8f931e9bb66174b41c.tar.gz
postgresql-984c23f6f5926f7cfb304b8f931e9bb66174b41c.zip
Fix oversight in handling of modifiedCols since f24523672d
Commit f24523672d fixed a memory leak by moving the modifiedCols bitmap into the per-row memory context. In the case of AFTER UPDATE triggers, the bitmap is however referenced from an event kept until the end of the query, resulting in a use-after-free bug. Fixed by copying the bitmap into the AfterTriggerEvents memory context, which is the one where we keep the trigger events. There's only one place that needs to do the copy, but the memory context may not exist yet. Doing that in a separate function seems more readable. Report by Alexander Pyhalov, fix by me. Backpatch to 13, where the bitmap was added to the event by commit 71d60e2aa0. Reported-by: Alexander Pyhalov Backpatch-through: 13 Discussion: https://postgr.es/m/acddb17c89b0d6cb940eaeda18c08bbe@postgrespro.ru
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/trigger.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 3a9b1dda3ff..49048c7e7df 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -3610,6 +3610,37 @@ afterTriggerCheckState(AfterTriggerShared evtshared)
return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
}
+/* ----------
+ * afterTriggerCopyBitmap()
+ *
+ * Copy bitmap into AfterTriggerEvents memory context, which is where the after
+ * trigger events are kept.
+ * ----------
+ */
+static Bitmapset *
+afterTriggerCopyBitmap(Bitmapset *src)
+{
+ Bitmapset *dst;
+ MemoryContext oldcxt;
+
+ if (src == NULL)
+ return NULL;
+
+ /* Create event context if we didn't already */
+ if (afterTriggers.event_cxt == NULL)
+ afterTriggers.event_cxt =
+ AllocSetContextCreate(TopTransactionContext,
+ "AfterTriggerEvents",
+ ALLOCSET_DEFAULT_SIZES);
+
+ oldcxt = MemoryContextSwitchTo(afterTriggers.event_cxt);
+
+ dst = bms_copy(src);
+
+ MemoryContextSwitchTo(oldcxt);
+
+ return dst;
+}
/* ----------
* afterTriggerAddEvent()
@@ -5726,7 +5757,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
new_shared.ats_table = transition_capture->tcs_private;
else
new_shared.ats_table = NULL;
- new_shared.ats_modifiedcols = modifiedCols;
+ new_shared.ats_modifiedcols = afterTriggerCopyBitmap(modifiedCols);
afterTriggerAddEvent(&afterTriggers.query_stack[afterTriggers.query_depth].events,
&new_event, &new_shared);