Skip to content

Commit 21f5bf8

Browse files
committed
Fix resource initialization order to prevent UB in destructor
Move tw_init(&conn->cancel_tw) before interrupt_mutex creation. If interrupt_mutex creation fails, enif_release_resource triggers the destructor, which calls tw_destroy on conn->cancel_tw. Without this change, tw_destroy would be called on an uninitialized condvar.
1 parent ae4ee81 commit 21f5bf8

1 file changed

Lines changed: 9 additions & 7 deletions

File tree

c_src/sqlite3_nif.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -543,19 +543,21 @@ exqlite_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
543543
}
544544
conn->db = db;
545545
conn->mutex = mutex;
546+
547+
// Initialize cancellable busy handler fields early so destructor can safely
548+
// call tw_destroy even if subsequent initialization steps fail.
549+
tw_init(&conn->cancel_tw);
550+
conn->cancelled = 0;
551+
conn->busy_timeout_ms = 2000; // default matches sqlite3_busy_timeout(db, 2000)
552+
conn->callback_env = NULL;
553+
546554
conn->interrupt_mutex = enif_mutex_create("exqlite:interrupt");
547555
if (conn->interrupt_mutex == NULL) {
548-
// conn->db and conn->mutex are set; the destructor will clean them up.
556+
// conn->db, conn->mutex, and conn->cancel_tw are set; destructor will clean them up.
549557
enif_release_resource(conn);
550558
return make_error_tuple(env, am_failed_to_create_mutex);
551559
}
552560

553-
// Initialize cancellable busy handler
554-
tw_init(&conn->cancel_tw);
555-
conn->cancelled = 0;
556-
conn->busy_timeout_ms = 2000; // default matches sqlite3_busy_timeout(db, 2000)
557-
conn->callback_env = NULL;
558-
559561
// Install our custom busy handler + progress handler
560562
sqlite3_busy_handler(db, exqlite_busy_handler, conn);
561563
sqlite3_progress_handler(db, 1000, exqlite_progress_handler, conn);

0 commit comments

Comments
 (0)