Skip to content

Commit 1b877d8

Browse files
committed
Clean up verbose comments in tests and C code
1 parent eb2bd26 commit 1b877d8

2 files changed

Lines changed: 0 additions & 85 deletions

File tree

c_src/sqlite3_nif.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,6 @@ exqlite_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
377377
connection_acquire_lock(conn);
378378

379379
// DB is already closed, nothing to do here.
380-
// Check must be inside the lock: two concurrent closes both pass
381-
// a pre-lock NULL check, and the second would call
382-
// sqlite3_get_autocommit(NULL) → segfault.
383380
if (conn->db == NULL) {
384381
connection_release_lock(conn);
385382
return am_ok;

test/exqlite/sqlite3_test.exs

Lines changed: 0 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -847,10 +847,6 @@ defmodule Exqlite.Sqlite3Test do
847847
:ok = Sqlite3.close(conn)
848848
end
849849

850-
# Verifies that concurrent interrupt/1 and close/1 are race-free.
851-
# exqlite_interrupt acquires interrupt_mutex (shared with close()) before
852-
# reading conn->db, and close() acquires it (while holding the conn lock,
853-
# after the running query has finished) before nulling conn->db.
854850
test "concurrent interrupt and close does not segfault" do
855851
for _ <- 1..500 do
856852
{:ok, conn} = Sqlite3.open(":memory:")
@@ -860,10 +856,6 @@ defmodule Exqlite.Sqlite3Test do
860856
end
861857
end
862858

863-
# Targets the two-concurrent-close TOCTOU:
864-
# Both threads pass the `conn->db == NULL` check outside the lock.
865-
# One closes and sets conn->db = NULL; the other then calls
866-
# sqlite3_get_autocommit(NULL) inside the lock → segfault.
867859
test "concurrent double close does not segfault" do
868860
for _ <- 1..200 do
869861
{:ok, conn} = Sqlite3.open(":memory:")
@@ -875,33 +867,17 @@ defmodule Exqlite.Sqlite3Test do
875867
end
876868
end
877869

878-
# Targets the missing NULL guard in exqlite_last_insert_rowid.
879-
# The function acquires the lock but never checks whether conn->db is NULL
880-
# before calling sqlite3_last_insert_rowid(conn->db).
881-
# After close() sets conn->db = NULL, the very next last_insert_rowid call
882-
# acquires the lock and dereferences the NULL pointer → segfault.
883-
# No concurrency is required; the crash is deterministic.
884870
test "last_insert_rowid after close does not segfault" do
885871
for _ <- 1..100 do
886872
{:ok, conn} = Sqlite3.open(":memory:")
887873
:ok = Sqlite3.execute(conn, "create table t (id integer primary key)")
888874
:ok = Sqlite3.execute(conn, "insert into t values (1)")
889875
{:ok, 1} = Sqlite3.last_insert_rowid(conn)
890876
:ok = Sqlite3.close(conn)
891-
# Unfixed: lock acquired, sqlite3_last_insert_rowid(NULL) → segfault.
892-
# Fixed: lock acquired, NULL check fires → {:error, :connection_closed}.
893877
assert {:error, :connection_closed} = Sqlite3.last_insert_rowid(conn)
894878
end
895879
end
896880

897-
# Targets the TOCTOU in exqlite_transaction_status.
898-
# The function checks !conn->db OUTSIDE the lock, then
899-
# acquires the lock and calls sqlite3_get_autocommit(conn->db) inside it.
900-
# If close() completes (setting conn->db = NULL) between that NULL check
901-
# and the lock acquisition, transaction_status calls
902-
# sqlite3_get_autocommit(NULL) → segfault.
903-
# This is a distinct bug from the double-close TOCTOU (Test 1): it involves
904-
# two *different* functions whose NULL checks are both outside their locks.
905881
test "concurrent close and transaction_status does not segfault" do
906882
for _ <- 1..500 do
907883
{:ok, conn} = Sqlite3.open(":memory:")
@@ -913,10 +889,6 @@ defmodule Exqlite.Sqlite3Test do
913889
end
914890
end
915891

916-
# Targets the TOCTOU in exqlite_changes:
917-
# conn->db is checked outside the lock; a concurrent close() can set
918-
# it to NULL between the check and the sqlite3_changes() call inside
919-
# the lock → sqlite3_changes(NULL) → segfault.
920892
test "concurrent close and changes does not segfault" do
921893
for _ <- 1..500 do
922894
{:ok, conn} = Sqlite3.open(":memory:")
@@ -928,9 +900,6 @@ defmodule Exqlite.Sqlite3Test do
928900
end
929901
end
930902

931-
# Targets the missing NULL guard in exqlite_serialize:
932-
# The function acquires the lock but calls sqlite3_serialize(conn->db, ...)
933-
# without checking for NULL → sqlite3_serialize(NULL, ...) → segfault.
934903
test "serialize after close does not segfault" do
935904
for _ <- 1..50 do
936905
{:ok, conn} = Sqlite3.open(":memory:")
@@ -939,9 +908,6 @@ defmodule Exqlite.Sqlite3Test do
939908
end
940909
end
941910

942-
# Targets exqlite_enable_load_extension:
943-
# No lock is held and no NULL check is performed; after close sets
944-
# conn->db = NULL, sqlite3_enable_load_extension(NULL, ...) → segfault.
945911
test "enable_load_extension after close does not segfault" do
946912
for _ <- 1..50 do
947913
{:ok, conn} = Sqlite3.open(":memory:")
@@ -950,9 +916,6 @@ defmodule Exqlite.Sqlite3Test do
950916
end
951917
end
952918

953-
# Targets the missing NULL guard in exqlite_deserialize:
954-
# Acquires the lock then calls sqlite3_deserialize(conn->db, ...) without
955-
# a NULL check → sqlite3_deserialize(NULL, ...) → segfault.
956919
test "deserialize after close does not segfault" do
957920
{:ok, src} = Sqlite3.open(":memory:")
958921
{:ok, data} = Sqlite3.serialize(src, "main")
@@ -965,16 +928,11 @@ defmodule Exqlite.Sqlite3Test do
965928
end
966929
end
967930

968-
# Targets the missing lock release on sqlite3_malloc failure in exqlite_deserialize:
969-
# sqlite3_malloc(0) returns NULL, so an empty binary triggers the error path.
970-
# Without the fix the lock is never released and any subsequent call deadlocks.
971931
test "deserialize malloc failure releases the connection lock" do
972932
{:ok, conn} = Sqlite3.open(":memory:")
973933

974-
# sqlite3_malloc(0) → NULL → hits the error return. Bug: lock not released.
975934
assert {:error, _} = Sqlite3.deserialize(conn, "main", <<>>)
976935

977-
# close/1 needs the lock. If it was leaked above, this will deadlock.
978936
task = Task.async(fn -> Sqlite3.close(conn) end)
979937
result = Task.yield(task, 500)
980938
Task.shutdown(task, :brutal_kill)
@@ -983,9 +941,6 @@ defmodule Exqlite.Sqlite3Test do
983941
"close deadlocked after failed deserialize (lock not released)"
984942
end
985943

986-
# Targets the missing NULL guard in exqlite_set_update_hook:
987-
# Acquires the lock then calls sqlite3_update_hook(conn->db, ...) without
988-
# a NULL check → sqlite3_update_hook(NULL, ...) → segfault.
989944
test "set_update_hook after close does not segfault" do
990945
for _ <- 1..50 do
991946
{:ok, conn} = Sqlite3.open(":memory:")
@@ -994,9 +949,6 @@ defmodule Exqlite.Sqlite3Test do
994949
end
995950
end
996951

997-
# Targets conn->db NULL dereference in exqlite_errmsg (connection branch).
998-
# After close(), conn->db is NULL. exqlite_errmsg calls
999-
# sqlite3_errmsg(conn->db) without a NULL guard → segfault.
1000952
test "errmsg conn after close does not segfault" do
1001953
for _ <- 1..50 do
1002954
{:ok, conn} = Sqlite3.open(":memory:")
@@ -1005,9 +957,6 @@ defmodule Exqlite.Sqlite3Test do
1005957
end
1006958
end
1007959

1008-
# Targets misleading return value in exqlite_errmsg (statement branch).
1009-
# After release(), statement->statement is NULL. The NIF should return
1010-
# nil (no error message available), not {:error, :connection_closed}.
1011960
test "errmsg stmt after release returns nil" do
1012961
for _ <- 1..50 do
1013962
{:ok, conn} = Sqlite3.open(":memory:")
@@ -1018,10 +967,6 @@ defmodule Exqlite.Sqlite3Test do
1018967
end
1019968
end
1020969

1021-
# Targets bind/2 crash when statement is released.
1022-
# bind_parameter_count returns {:error, :invalid_statement} after release,
1023-
# but bind/2 assumes it always returns an integer, causing a confusing
1024-
# crash instead of a clean error.
1025970
test "bind after release returns error" do
1026971
for _ <- 1..50 do
1027972
{:ok, conn} = Sqlite3.open(":memory:")
@@ -1034,11 +979,6 @@ defmodule Exqlite.Sqlite3Test do
1034979
end
1035980

1036981
describe ".step, .columns, .multi_step, .reset, .bind_* after release" do
1037-
# Targets statement use-after-release in exqlite_step.
1038-
# After Sqlite3.release(conn, stmt), statement->statement is set to NULL
1039-
# under the connection lock. exqlite_step acquires the connection lock
1040-
# and then calls sqlite3_step(statement->statement) without checking for
1041-
# NULL → sqlite3_step(NULL) → segfault.
1042982
test "step after release does not segfault" do
1043983
for _ <- 1..50 do
1044984
{:ok, conn} = Sqlite3.open(":memory:")
@@ -1050,11 +990,6 @@ defmodule Exqlite.Sqlite3Test do
1050990
end
1051991
end
1052992

1053-
# Targets statement use-after-release in exqlite_columns.
1054-
# After Sqlite3.release(conn, stmt), statement->statement is NULL.
1055-
# exqlite_columns acquires the statement lock (= connection lock) and
1056-
# calls sqlite3_column_count(statement->statement) without checking for
1057-
# NULL → sqlite3_column_count(NULL) → segfault.
1058993
test "columns after release does not segfault" do
1059994
for _ <- 1..50 do
1060995
{:ok, conn} = Sqlite3.open(":memory:")
@@ -1066,11 +1001,6 @@ defmodule Exqlite.Sqlite3Test do
10661001
end
10671002
end
10681003

1069-
# Targets statement use-after-release in exqlite_multi_step.
1070-
# After Sqlite3.release(conn, stmt), statement->statement is NULL.
1071-
# The pre-lock check catches the case where release happened before
1072-
# the call, and the inside-lock check catches the case where release
1073-
# races with the lock acquisition.
10741004
test "multi_step after release does not segfault" do
10751005
for _ <- 1..50 do
10761006
{:ok, conn} = Sqlite3.open(":memory:")
@@ -1082,10 +1012,6 @@ defmodule Exqlite.Sqlite3Test do
10821012
end
10831013
end
10841014

1085-
# Targets statement use-after-release in exqlite_reset.
1086-
# After Sqlite3.release(conn, stmt), statement->statement is NULL.
1087-
# exqlite_reset acquires the statement lock and calls sqlite3_reset(NULL)
1088-
# without checking for NULL → segfault.
10891015
test "reset after release does not segfault" do
10901016
for _ <- 1..50 do
10911017
{:ok, conn} = Sqlite3.open(":memory:")
@@ -1097,10 +1023,6 @@ defmodule Exqlite.Sqlite3Test do
10971023
end
10981024
end
10991025

1100-
# Targets statement use-after-release in exqlite_bind_parameter_count.
1101-
# After Sqlite3.release(conn, stmt), statement->statement is NULL.
1102-
# exqlite_bind_parameter_count acquires the statement lock and calls
1103-
# sqlite3_bind_parameter_count(NULL) → segfault.
11041026
test "bind_parameter_count after release does not segfault" do
11051027
for _ <- 1..50 do
11061028
{:ok, conn} = Sqlite3.open(":memory:")
@@ -1111,10 +1033,6 @@ defmodule Exqlite.Sqlite3Test do
11111033
end
11121034
end
11131035

1114-
# Targets statement use-after-release in the bind_* NIFs.
1115-
# After Sqlite3.release(conn, stmt), statement->statement is NULL.
1116-
# Each bind_* NIF acquires the statement lock and calls the SQLite bind
1117-
# function without checking for NULL → segfault.
11181036
test "bind_text after release does not segfault" do
11191037
for _ <- 1..50 do
11201038
{:ok, conn} = Sqlite3.open(":memory:")

0 commit comments

Comments
 (0)