Symptom
PR #590 CI red on all 12 matrix jobs: tests/issue582_plink_revitalization.phpt passes all assertions, then Segmentation fault (core dumped) Termsig=11 at process shutdown.
Root cause (gdb backtrace, reproduced locally 3/3 with CI env FIREBIRD_DB_DIR=/tmp)
#0 fb::StatementWrapper::closeCursor (fb_statement.hpp:418) result_set_->close()
#1 fbs_close_cursor (firebird_utils.cpp:1503)
#2 php_fbird_free_query_rsrc (fbird_query_prepare.c:197)
#3 zend_shutdown_executor_values (request shutdown, resource dtor)
fbird_drop_db() / fbc_disconnect() delete the fb::Connection (RAII releases the IAttachment and every dependent interface).
- Query result resources still alive (not yet freed by userland) keep
StatementWrappers whose statement_/result_set_ pointers are now dead.
- At request shutdown the query dtor calls
fbs_close_cursor/fbs_free on those dead interfaces -> UAF.
fbird_drop_db() already nulls transaction handles (same lifetime-coupling pattern, fbird_connection.c:986-991) but has no statement invalidation - and fbird_query has no link back-reference, so the dtor cannot check liveness.
Why CI only (local weekend run was green)
Local dev env FIREBIRD_DB_DIR=/firebird (bind volume): best-effort cleanup drop behaves differently; with CI env FIREBIRD_DB_DIR=/tmp (server-writable) the sequence is deterministic. Same test, same build: /tmp = 3/3 crash, /firebird = 3/3 pass.
Fix direction
Mirror the transaction-nulling pattern at the connection layer: intrusive per-thread registry of live StatementWrappers keyed by IAttachment identity; on connection death (fbc_disconnect, fbc_drop_database - all exit paths) neutralize dependent wrappers (null handles WITHOUT release - they died with the attachment). Existing null-guards in closeCursor()/free() make subsequent dtor calls no-ops.
Siblings (deferred): BlobWrapper / batch wrappers hold dead interfaces the same way - no observed crash; note ceiling.
Blocks
Symptom
PR #590 CI red on all 12 matrix jobs:
tests/issue582_plink_revitalization.phptpasses all assertions, thenSegmentation fault (core dumped)Termsig=11 at process shutdown.Root cause (gdb backtrace, reproduced locally 3/3 with CI env
FIREBIRD_DB_DIR=/tmp)fbird_drop_db()/fbc_disconnect()delete thefb::Connection(RAII releases the IAttachment and every dependent interface).StatementWrappers whosestatement_/result_set_pointers are now dead.fbs_close_cursor/fbs_freeon those dead interfaces -> UAF.fbird_drop_db()already nulls transaction handles (same lifetime-coupling pattern, fbird_connection.c:986-991) but has no statement invalidation - andfbird_queryhas no link back-reference, so the dtor cannot check liveness.Why CI only (local weekend run was green)
Local dev env
FIREBIRD_DB_DIR=/firebird(bind volume): best-effort cleanup drop behaves differently; with CI envFIREBIRD_DB_DIR=/tmp(server-writable) the sequence is deterministic. Same test, same build: /tmp = 3/3 crash, /firebird = 3/3 pass.Fix direction
Mirror the transaction-nulling pattern at the connection layer: intrusive per-thread registry of live StatementWrappers keyed by IAttachment identity; on connection death (
fbc_disconnect,fbc_drop_database- all exit paths) neutralize dependent wrappers (null handles WITHOUT release - they died with the attachment). Existing null-guards incloseCursor()/free()make subsequent dtor calls no-ops.Siblings (deferred): BlobWrapper / batch wrappers hold dead interfaces the same way - no observed crash; note ceiling.
Blocks