[Bug] Usage of stale dead_items pointer in parallel vacuum

From: Kevin Oommen Anish <kevin(dot)o(at)zohocorp(dot)com>
To: "pgsql-bugs" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: [Bug] Usage of stale dead_items pointer in parallel vacuum
Date: 2025-10-01 15:55:53
Message-ID: 199a07cbdfc.7a1c4aac25838.1675074408277594551@zohocorp.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Hello Developers,    

We have discovered a bug in the dead_items_reset function in PG v17 specifically near the parallel_vacuum_reset_dead_items function() invocation. The bug is still prevalent in the latest version v18 as well. Although it was introduced in v17, it was detected while running the vacuum.sql regression tests which were introduced in PG v17.5.

In dead_items_reset function, we destroy and recreate the shared TidStore by invoking the parallel_vacuum_reset_dead_items() function. However, after the reallocation, the vacrel->dead_items pointer is not updated to point to the newly allocated TidStore. As a result, the leader process continues to hold a pointer to the destroyed TidStore. As a result, subsequent calls by the leader process to dead_items_add() go through this stale pointer, resulting in a use-after-free.

However this goes unnoticed since the freeing and reallocation of the shared TidStore (vacrel->pvs->dead_items) are so close to each other, that the AllocSet memory context always hands back the exact same chunk of memory that was freed previously, making the stale vacrel->dead_items pointer still appear valid even though it technically points to freed storage.

This issue was reproduced while running the existing regression tests from vacuum.sql with our custom malloc allocator implementation. For your reference, we have previously shared our custom malloc allocator implementation in a separate bug fix. (message ID: mailto:1936493cc38(dot)68cb2ef27266(dot)7456585136086197135(at)zohocorp(dot)com ).The corresponding crash backtrace is attached as well.

Failed regression:

CREATE TABLE pvactst2 (i INT) WITH (autovacuum_enabled = off);

INSERT INTO pvactst2 SELECT generate_series(1, 1000);

CREATE INDEX ON pvactst2 (i);

CREATE INDEX ON pvactst2 (i);
SET min_parallel_index_scan_size to 0;
SET maintenance_work_mem TO 64;

INSERT INTO pvactst2 SELECT generate_series(1, 1000);

DELETE FROM pvactst2 WHERE i < 1000;

VACUUM (PARALLEL 2) pvactst2;

Please let me know if you have any questions or would like further details.

Thanks & Regards,

Kevin Oommen Anish

Member Technical Staff

ZOHO Corporation

Attachment Content-Type Size
crash_back_trace.txt text/plain 13.7 KB
dead_items_reset_fix.patch application/octet-stream 870 bytes

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Pavel Stehule 2025-10-01 18:16:26 Re: IN List operator , where list of values are over a number of lines
Previous Message White, Ian Keith 2025-10-01 15:12:22 IN List operator , where list of values are over a number of lines