The VM can crash when the Sqlite3.step(conn, statement) is called with statement prepared for different connection. To illustrate with code:
{:ok, connection_a} = Sqlite3.open(":memory:")
{:ok, connection_b} = Sqlite3.open(":memory:")
{:ok, statement_b} = Sqlite3.prepare(connection_b, query)
Sqlite3.step(connection_a, statement_b)
This is the complete script that reproduces it 60-70% of time for me (not always, as it's a race condition):
alias Exqlite.Sqlite3
query = """
WITH RECURSIVE counter(value) AS (
SELECT 0
UNION ALL
SELECT value + 1 FROM counter WHERE value < 100000
)
SELECT randomblob(4194304) FROM counter WHERE value = 100000
"""
Enum.each(1..50, fn _iteration ->
{:ok, connection_a} = Sqlite3.open(":memory:")
{:ok, connection_b} = Sqlite3.open(":memory:")
try do
{:ok, statement_b} = Sqlite3.prepare(connection_b, query)
parent = self()
step_started_ref = make_ref()
step_task =
Task.async(fn ->
send(parent, {:cross_connection_step_started, step_started_ref})
Sqlite3.step(connection_a, statement_b)
end)
receive do
{:cross_connection_step_started, ^step_started_ref} -> :ok
after
1_000 -> raise "timed out waiting for cross-connection step to start"
end
Process.sleep(1)
release_task =
Task.async(fn -> Sqlite3.release(connection_b, statement_b) end)
Task.await(step_task, 30_000)
:ok = Task.await(release_task, 30_000)
after
Sqlite3.close(connection_a)
Sqlite3.close(connection_b)
end
end)
The solutions is IMO to add a check if conn == statement->conn probably somewhere around here, before acquiring the lock. But I'm not sure what should be the outcome if it does not match. I'd lean towards the exception, not returning an error tuple, but wanted to consult first.
AI disclosure
The issue was initially flagged by AI review and I used AI help to figure out the reproduction script.
The VM can crash when the
Sqlite3.step(conn, statement)is called with statement prepared for different connection. To illustrate with code:This is the complete script that reproduces it 60-70% of time for me (not always, as it's a race condition):
The solutions is IMO to add a check if
conn == statement->connprobably somewhere around here, before acquiring the lock. But I'm not sure what should be the outcome if it does not match. I'd lean towards the exception, not returning an error tuple, but wanted to consult first.AI disclosure
The issue was initially flagged by AI review and I used AI help to figure out the reproduction script.