The problem is that heap_force_common() walks the caller-supplied tid[] with OffsetNumber indexes. OffsetNumber is a uint16, while ntids is an int, so an array longer than 65535 makes the next-index update wrap. The outer loop then never reaches next_start_ptr == ntids and keeps reprocessing the same page until cancel. Those variables have been OffsetNumber since pg_surgery was added in 34a947ca13e.
Bug reference: 19607 Logged by: Yuelin Wang Email address: 1217816127@qq.com PostgreSQL version: 19beta2 Operating system: Linux (Ubuntu 24.04, x86_64) Description:
### Summary
In `contrib/pg_surgery/heap_surgery.c`, a huge TID array can truncate an index into `OffsetNumber`. The loop no longer reaches its end condition and the statement keeps running until cancellation. This is a SQL reachable denial of service when `pg_surgery` is installed.
### PoC
SQL script:
```sql CREATE EXTENSION IF NOT EXISTS pg_surgery;
CREATE TABLE vuln_surgery_loop(a int); INSERT INTO vuln_surgery_loop SELECT g FROM generate_series(1, 300) AS g;
The call remains active until `statement_timeout`. A finite array pass of this size should complete quickly, so the timeout confirms the integer truncation induced infinite loop.