Re: Server crash: Use-after-free in AfterTriggerEndQuery() - Mailing list pgsql-hackers

From Amit Langote
Subject Re: Server crash: Use-after-free in AfterTriggerEndQuery()
Date
Msg-id CA+HiwqGBy7ED8+drGY1j6GYKoi0vXZgoBSaH5GsBgiBY3Qd1xg@mail.gmail.com
Whole thread
In response to Server crash: Use-after-free in AfterTriggerEndQuery()  (Amul Sul <sulamul@gmail.com>)
Responses Re: Server crash: Use-after-free in AfterTriggerEndQuery()
List pgsql-hackers
On Tue, May 5, 2026 at 15:37 Amul Sul <sulamul@gmail.com> wrote:
Hi,

The crash occurs when the per-query firing loop in
AfterTriggerEndQuery() exits via the "all fired" path. If
afterTriggerInvokeEvents() reallocated query_stack while firing, the
loop's local qs pointer is left dangling, and the subsequent
FireAfterTriggerBatchCallbacks(qs->batch_callbacks) reads
batch_callbacks from the freed memory and crashes.

Here is the reproducible test that has an AFTER INSERT trigger on a
referenced table that recursively inserts rows into itself:

--
create table trigger_recursive_pk (id int primary key);
create table trigger_recursive_fk (id int references trigger_recursive_pk(id));
insert into trigger_recursive_pk select g from generate_series(1, 15) g;

create function trigger_recursive_fn() returns trigger language plpgsql as $$
begin
    if new.id < 10 then
        insert into trigger_recursive_fk values (new.id + 1);
    end if;
    return new;
end$$;

create trigger trigger_recursive after insert on trigger_recursive_fk
    for each row execute function trigger_recursive_fn();

insert into trigger_recursive_fk values (1);
--

The attached patch fixes the reported issue by recomputing qs
immediately before calling FireAfterTriggerBatchCallbacks().

Thanks Amul for the report. I'll look at this on Thursday when I'm back at work.

- Amit

pgsql-hackers by date:

Previous
From: Peter Eisentraut
Date:
Subject: Re: [PATCH] Clean up property graph error messages
Next
From: Dmitrii Bondar
Date:
Subject: Re: Pgbench: remove synchronous prepare