FirebirdSQL / firebird

Firebird server, client and tools
https://www.firebirdsql.org/
1.19k stars 204 forks source link

Engine could crash when executing some trigger(s) while another attachment modifies them #8079

Closed hvlad closed 1 month ago

hvlad commented 1 month ago

The bug is very hard to reproduce. It was found using crash dump from customer. I've created artificial test case that shows access to the already released memory. Unfortunately, it not crashes in RELEASE builds, as there is no load on memory manager in test and released memory is not reused. I've added assert that clearly shows the problem for devs (at least):

void TrigVector::release(thread_db* tdbb)
{
+   fb_assert(useCount.value() > 0);

    if (--useCount == 0)
    {
        decompile(tdbb);
        delete this;
    }
}

The test case is as follows:

  1. Prepare test database:
create database '...';

create table t1(id int);
create table t2(id int);
commit;

set term ^;
create or alter procedure sp_ins_t1(id int)
as
begin
  execute statement ('insert into t1 (id) values(?)') (:id);
end
^
create or alter procedure sp_ins_t2(id int)
as
begin
  insert into t2 values (:id);
end
^
create or alter trigger t1_bi1
  for t1 before insert position 1
as
declare x int;
begin
  select count(*) from t1 into :x;
  execute procedure sp_ins_t2(new.id);
end
^
set term ;^

commit;

select * from t1;
select * from t2;
commit;
exit;
  1. Run two isql sessions and connect to the database created above. Each step have comment with N.M where N is number of session and M is number of step
-- 1.1
set auto off;
commit;
execute procedure sp_ins_t1(1);

-- 2.2
set auto off;
alter table t1 add f2 int;
commit;

-- 1.3
select * from t1;

-- 2.4
set term ^;
alter trigger t1_bi1
as
begin
  insert into t2 values(-new.id);
end
^
create or alter procedure sp_ins_t2(id int, x int)
as
begin
  insert into t2 values (:id * 100);
end
^
set term ;^
commit;

-- 1.5
execute procedure sp_ins_t1(2);   

Here DEBUG build will crash on assert (see above)

Stack trace ucrtbased.dll!issue_debug_notification(const wchar_t * const message=0x00007ffa5e5fb9f0) Line 28 ucrtbased.dll!__acrt_report_runtime_error(const wchar_t * message=0x00007ffa5e5fb9f0) Line 154 ucrtbased.dll!abort() Line 61 engine13.dll!fb_assert_impl(const char * msg=0x00007ffa4cad19b0, const char * file=0x00007ffa4cad1990, int line=9862, bool do_abort=true) Line 49 engine13.dll!Jrd::TrigVector::release(Jrd::thread_db * tdbb=0x000000000411ce60) Line 9862 engine13.dll!MET_release_triggers(Jrd::thread_db * tdbb=0x000000000411ce60, Jrd::TrigVector * * vector_ptr=0x000000000411bad8, bool destroy=true) Line 10452 engine13.dll!`EXE_execute_triggers'::`1'::catch$7() Line 1434 [External Code] engine13.dll!EXE_execute_triggers(Jrd::thread_db * tdbb=0x000000000411ce60, Jrd::TrigVector * * triggers=0x000000000951c558, Jrd::record_param * old_rpb=0x0000000000000000, Jrd::record_param * new_rpb=0x0000000006fda310, TriggerAction trigger_action=TRIGGER_INSERT, Jrd::StmtNode::WhichTrigger which_trig=PRE_TRIG, int ddl_action=0) Line 1348 engine13.dll!Jrd::StoreNode::store(Jrd::thread_db * tdbb=0x000000000411ce60, Jrd::Request * request=0x00000000075adfa0, Jrd::StmtNode::WhichTrigger whichTrig=ALL_TRIGS) Line 8880 engine13.dll!Jrd::StoreNode::execute(Jrd::thread_db * tdbb=0x000000000411ce60, Jrd::Request * request=0x00000000075adfa0, Jrd::StmtNode::ExeState * exeState=0x000000000411c0e8) Line 8825
hvlad commented 1 month ago

Reopen for backporting