Skip to content

Segmentation fault with Sqlite3.step #353

Description

@katafrakt

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions