Skip to content

mem(uaf): query result dtor SIGSEGV when connection died (drop_db/disconnect) - statements never invalidated, blocks #582 CI #591

Description

@satwareAG-ironMike

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions