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

Attachment: 0001-Fix-propgraph-orphan-static-list-use-after-free.patch
Description: Binary data

Reply via email to