Thread
-
[PATCH] Fix use-after-free of propgraph orphan static lists on xact abort
SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com> — 2026-05-12T17:52:52Z
Hi hackers, My PG19 fuzz tests detected the $subject issue in dependency.c. Repro: It is not 100% deterministic because of the timeout, if hard to follow can write an injection point test. \set ON_ERROR_STOP off CREATE TABLE n1(id int PRIMARY KEY, name text); -- Many indexes ensure the cascade takes enough time after the propgraph -- element's deleteOneObject() for statement_timeout to fire. DO $$ BEGIN FOR i IN 1..50 LOOP EXECUTE format('CREATE INDEX idx_%s ON n1 (id) WHERE id > %s', i, i); END LOOP; END $$; CREATE PROPERTY GRAPH pg1 VERTEX TABLES (n1 LABEL l1 PROPERTIES(id, name)); CREATE TABLE n2(id int PRIMARY KEY, name text); CREATE PROPERTY GRAPH pg2 VERTEX TABLES (n2 LABEL l2 PROPERTIES(id, name)); SET statement_timeout = '3ms'; DROP TABLE n1 CASCADE; RESET statement_timeout; DROP TABLE n2 CASCADE; SELECT 1 AS status; 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 trips 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. Thanks, Satya