0001-Fix-propgraph-orphan-static-list-use-after-free.patch
application/octet-stream
Filename: 0001-Fix-propgraph-orphan-static-list-use-after-free.patch
Type: application/octet-stream
Part: 0
From 0df518b593a290d6d9dce11b20bcd5d6cb90f37d Mon Sep 17 00:00:00 2001
From: Satya Narlapuram <satyanarlapuram@gmail.com>
Date: Tue, 12 May 2026 16:24:14 +0000
Subject: [PATCH] Fix use-after-free of propgraph orphan static lists on xact
abort
The static lists propgraph_orphan_label_graphids and
propgraph_orphan_property_graphids in dependency.c are allocated in
TopTransactionContext during deleteOneObject(). They are only reset
on the success path of performDeletion()/performMultipleDeletions(),
in run_deferred_propgraph_orphan_cleanup().
If a transaction aborts after the lists have been populated, for example
due to statement_timeout, or any other error thrown during
the cascade), AbortTransaction() frees TopTransactionContext but the
static pointers remain set. A subsequent property graph cascade in
the same backend session then passes the dangling pointers to
list_append_unique_oid(), which walks freed memory. With assertions
enabled this manifests as:
TRAP: failed Assert("IsOidList(list)"), File: "list.c", Line: 726
Without assertions this silently corrupts memory.
Fix by resetting both statics to NIL in the PG_FINALLY() blocks of
performDeletion() and performMultipleDeletions(), which execute on
both success and error paths.
---
src/backend/catalog/dependency.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 489be33eb0..7c4f23d946 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -432,6 +432,18 @@ performDeletion(const ObjectAddress *object,
}
PG_FINALLY();
{
+ /*
+ * If we are the outermost performDeletion() and an error occurred,
+ * the propgraph orphan lists are allocated in TopTransactionContext
+ * which will be freed by AbortTransaction(). Reset the static
+ * pointers to NIL so that a subsequent property graph cascade in
+ * the same backend session does not walk freed memory.
+ */
+ if (performDeletion_depth == 1)
+ {
+ propgraph_orphan_label_graphids = NIL;
+ propgraph_orphan_property_graphids = NIL;
+ }
performDeletion_depth--;
}
PG_END_TRY();
@@ -574,6 +586,12 @@ performMultipleDeletions(const ObjectAddresses *objects,
}
PG_FINALLY();
{
+ /* See comment in performDeletion's PG_FINALLY block. */
+ if (performDeletion_depth == 1)
+ {
+ propgraph_orphan_label_graphids = NIL;
+ propgraph_orphan_property_graphids = NIL;
+ }
performDeletion_depth--;
}
PG_END_TRY();
--
2.43.0