Skip to content

Commit f01563f

Browse files
committed
Reproduce race-condition between close & prepare
1 parent 4fc3a55 commit f01563f

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

c_src/sqlite3.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135367,6 +135367,12 @@ static int sqlite3LockAndPrepare(
135367135367
if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
135368135368
return SQLITE_MISUSE_BKPT;
135369135369
}
135370+
// sleep only for insert stmt
135371+
if (strncmp(zSql, "insert into debug", 17) == 0) {
135372+
printf("sqlite3LockAndPrepare(): do not acquire the mutex, wait for sqlite3LeaveMutexAndCloseZombie() execute\n");
135373+
sqlite3_sleep(1000);
135374+
printf("sqlite3LockAndPrepare(): done waiting, proceeding with the execution\n");
135375+
}
135370135376
sqlite3_mutex_enter(db->mutex);
135371135377
sqlite3BtreeEnterAll(db);
135372135378
do{
@@ -172100,6 +172106,8 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
172100172106
db->xAutovacDestr(db->pAutovacPagesArg);
172101172107
}
172102172108
sqlite3_mutex_leave(db->mutex);
172109+
printf("sqlite3LeaveMutexAndCloseZombie(): critical-section execution is done, the mutex is released. Wait for sqlite3LockAndPrepare() to proceeds before we free db\n");
172110+
sqlite3_sleep(1500);
172103172111
db->eOpenState = SQLITE_STATE_CLOSED;
172104172112
sqlite3_mutex_free(db->mutex);
172105172113
assert( sqlite3LookasideUsed(db,0)==0 );

test/exqlite/timeout_segfault_test.exs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
defmodule Exqlite.TimeoutSegfaultTest do
22
use ExUnit.Case
33

4+
alias Exqlite.Sqlite3
5+
46
setup do
57
{:ok, path} = Temp.path()
68
on_exit(fn -> File.rm(path) end)
@@ -36,4 +38,17 @@ defmodule Exqlite.TimeoutSegfaultTest do
3638
end)
3739
|> Stream.run()
3840
end
41+
42+
test "race condition", %{path: path} do
43+
{:ok, conn} = Sqlite3.open(path)
44+
:ok = Sqlite3.execute(conn, "create table debug(id integer)")
45+
46+
spawn_link(fn ->
47+
Sqlite3.prepare(conn, "insert into debug(id) values (1)")
48+
end)
49+
50+
# ensure `Sqlite3.prepare()` is executed before we attempt to close the connection
51+
Process.sleep(100)
52+
:ok = Sqlite3.close(conn)
53+
end
3954
end

0 commit comments

Comments
 (0)