Skip to content

Commit 96ac49c

Browse files
committed
fix(sqlite3): avoid reentrant deadlock in Statement::new
sqlite3_prepare_v2 can synchronously invoke the authorizer callback, which may call back into Connection methods (e.g. set_authorizer) that require the same db lock. Holding db_lock across the prepare() call caused a self-deadlock when a callback re-entered the connection. Release the lock after sql_limit check and copy the raw handle before calling prepare(), so FFI calls that can trigger Python re-entrancy happen outside the lock scope. Fixes hang in test_authorizer_concurrent_mutation_in_call
1 parent d809353 commit 96ac49c

1 file changed

Lines changed: 6 additions & 4 deletions

File tree

crates/stdlib/src/_sqlite3.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2798,12 +2798,14 @@ mod _sqlite3 {
27982798
}
27992799
let sql_cstr = sql.to_cstring(vm)?;
28002800

2801-
let db = connection.db_lock(vm)?;
2802-
2803-
db.sql_limit(sql.byte_len(), vm)?;
2801+
let raw = {
2802+
let db = connection.db_lock(vm)?;
2803+
db.sql_limit(sql.byte_len(), vm)?;
2804+
**db
2805+
};
28042806

28052807
let mut tail = null();
2806-
let st = db.prepare(sql_cstr.as_ptr(), &mut tail, vm)?;
2808+
let st = raw.prepare(sql_cstr.as_ptr(), &mut tail, vm)?;
28072809

28082810
let Some(st) = st else {
28092811
return Ok(None);

0 commit comments

Comments
 (0)