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.