Skip to content

Commit d1c6edd

Browse files
committed
Fix use-after-free bug with AfterTriggersTableData.storeslot
AfterTriggerSaveEvent() wrongly allocates the slot in execution-span memory context, whereas the correct thing is to allocate it in a transaction-span context, because that's where the enclosing AfterTriggersTableData instance belongs into. Backpatch to 12 (the test back to 11, where it works well with no code changes, and it's good to have to confirm that the case was previously well supported); this bug seems introduced by commit ff11e7f. Reported-by: Bertrand Drouvot <bdrouvot@amazon.com> Author: Amit Langote <amitlangote09@gmail.com> Discussion: https://postgr.es/m/39a71864-b120-5a5c-8cc5-c632b6f16761@amazon.com
1 parent de19e5e commit d1c6edd

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

src/test/regress/expected/triggers.out

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3027,3 +3027,62 @@ drop table self_ref;
30273027
drop function dump_insert();
30283028
drop function dump_update();
30293029
drop function dump_delete();
3030+
-- verify transition table conversion slot's lifetime
3031+
-- https://postgr.es/m/39a71864-b120-5a5c-8cc5-c632b6f16761@amazon.com
3032+
create table convslot_test_parent (col1 text primary key);
3033+
create table convslot_test_child (col1 text primary key,
3034+
foreign key (col1) references convslot_test_parent(col1) on delete cascade on update cascade
3035+
);
3036+
alter table convslot_test_child add column col2 text not null default 'tutu';
3037+
insert into convslot_test_parent(col1) values ('1');
3038+
insert into convslot_test_child(col1) values ('1');
3039+
insert into convslot_test_parent(col1) values ('3');
3040+
insert into convslot_test_child(col1) values ('3');
3041+
create or replace function trigger_function1()
3042+
returns trigger
3043+
language plpgsql
3044+
AS $$
3045+
begin
3046+
raise notice 'trigger = %, old_table = %',
3047+
TG_NAME,
3048+
(select string_agg(old_table::text, ', ' order by col1) from old_table);
3049+
return null;
3050+
end; $$;
3051+
create or replace function trigger_function2()
3052+
returns trigger
3053+
language plpgsql
3054+
AS $$
3055+
begin
3056+
raise notice 'trigger = %, new table = %',
3057+
TG_NAME,
3058+
(select string_agg(new_table::text, ', ' order by col1) from new_table);
3059+
return null;
3060+
end; $$;
3061+
create trigger but_trigger after update on convslot_test_child
3062+
referencing new table as new_table
3063+
for each statement execute function trigger_function2();
3064+
update convslot_test_parent set col1 = col1 || '1';
3065+
NOTICE: trigger = but_trigger, new table = (11,tutu), (31,tutu)
3066+
create or replace function trigger_function3()
3067+
returns trigger
3068+
language plpgsql
3069+
AS $$
3070+
begin
3071+
raise notice 'trigger = %, old_table = %, new table = %',
3072+
TG_NAME,
3073+
(select string_agg(old_table::text, ', ' order by col1) from old_table),
3074+
(select string_agg(new_table::text, ', ' order by col1) from new_table);
3075+
return null;
3076+
end; $$;
3077+
create trigger but_trigger2 after update on convslot_test_child
3078+
referencing old table as old_table new table as new_table
3079+
for each statement execute function trigger_function3();
3080+
update convslot_test_parent set col1 = col1 || '1';
3081+
NOTICE: trigger = but_trigger, new table = (111,tutu), (311,tutu)
3082+
NOTICE: trigger = but_trigger2, old_table = (11,tutu), (31,tutu), new table = (111,tutu), (311,tutu)
3083+
create trigger bdt_trigger after delete on convslot_test_child
3084+
referencing old table as old_table
3085+
for each statement execute function trigger_function1();
3086+
delete from convslot_test_parent;
3087+
NOTICE: trigger = bdt_trigger, old_table = (111,tutu), (311,tutu)
3088+
drop table convslot_test_child, convslot_test_parent;

src/test/regress/sql/triggers.sql

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2274,3 +2274,68 @@ drop table self_ref;
22742274
drop function dump_insert();
22752275
drop function dump_update();
22762276
drop function dump_delete();
2277+
2278+
-- verify transition table conversion slot's lifetime
2279+
-- https://postgr.es/m/39a71864-b120-5a5c-8cc5-c632b6f16761@amazon.com
2280+
create table convslot_test_parent (col1 text primary key);
2281+
create table convslot_test_child (col1 text primary key,
2282+
foreign key (col1) references convslot_test_parent(col1) on delete cascade on update cascade
2283+
);
2284+
2285+
alter table convslot_test_child add column col2 text not null default 'tutu';
2286+
insert into convslot_test_parent(col1) values ('1');
2287+
insert into convslot_test_child(col1) values ('1');
2288+
insert into convslot_test_parent(col1) values ('3');
2289+
insert into convslot_test_child(col1) values ('3');
2290+
2291+
create or replace function trigger_function1()
2292+
returns trigger
2293+
language plpgsql
2294+
AS $$
2295+
begin
2296+
raise notice 'trigger = %, old_table = %',
2297+
TG_NAME,
2298+
(select string_agg(old_table::text, ', ' order by col1) from old_table);
2299+
return null;
2300+
end; $$;
2301+
2302+
create or replace function trigger_function2()
2303+
returns trigger
2304+
language plpgsql
2305+
AS $$
2306+
begin
2307+
raise notice 'trigger = %, new table = %',
2308+
TG_NAME,
2309+
(select string_agg(new_table::text, ', ' order by col1) from new_table);
2310+
return null;
2311+
end; $$;
2312+
2313+
create trigger but_trigger after update on convslot_test_child
2314+
referencing new table as new_table
2315+
for each statement execute function trigger_function2();
2316+
2317+
update convslot_test_parent set col1 = col1 || '1';
2318+
2319+
create or replace function trigger_function3()
2320+
returns trigger
2321+
language plpgsql
2322+
AS $$
2323+
begin
2324+
raise notice 'trigger = %, old_table = %, new table = %',
2325+
TG_NAME,
2326+
(select string_agg(old_table::text, ', ' order by col1) from old_table),
2327+
(select string_agg(new_table::text, ', ' order by col1) from new_table);
2328+
return null;
2329+
end; $$;
2330+
2331+
create trigger but_trigger2 after update on convslot_test_child
2332+
referencing old table as old_table new table as new_table
2333+
for each statement execute function trigger_function3();
2334+
update convslot_test_parent set col1 = col1 || '1';
2335+
2336+
create trigger bdt_trigger after delete on convslot_test_child
2337+
referencing old table as old_table
2338+
for each statement execute function trigger_function1();
2339+
delete from convslot_test_parent;
2340+
2341+
drop table convslot_test_child, convslot_test_parent;

0 commit comments

Comments
 (0)