Skip to content

Commit 5008551

Browse files
renatgalimovmceachen
authored andcommitted
Pass correct pointer to cleanup in ensure_vector_match error path
When the second vector fails to parse in ensure_vector_match(), the cleanup function for the first vector was called with 'a' (void**) instead of '*a' (void*). This caused sqlite3_free to be called with a stack address instead of the heap-allocated vector, resulting in a crash: malloc: Non-aligned pointer being freed Fatal error 6: Aborted The fix dereferences the pointer correctly, matching how cleanup is done in other error paths. This fix has a unit test that will crash without the patch.
1 parent a6fd0c9 commit 5008551

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

sqlite-vec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1155,7 +1155,7 @@ int ensure_vector_match(sqlite3_value *aValue, sqlite3_value *bValue, void **a,
11551155
if (rc != SQLITE_OK) {
11561156
*outError = sqlite3_mprintf("Error reading 2nd vector: %s", error);
11571157
sqlite3_free(error);
1158-
aCleanup(a);
1158+
aCleanup(*a);
11591159
return SQLITE_ERROR;
11601160
}
11611161

tests/test-loadable.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,31 @@ def test_vec_distance_cosine_zero_vector():
480480
assert vec_distance_cosine_bit(b"\xff", b"\x00") == 1.0
481481
assert vec_distance_cosine_bit(b"\x00", b"\x00") == 1.0
482482

483+
def test_ensure_vector_match_cleanup_on_second_vector_error():
484+
"""
485+
Test that ensure_vector_match properly cleans up the first vector
486+
when the second vector fails to parse.
487+
488+
This tests the fix for a bug where aCleanup(a) was called instead of
489+
aCleanup(*a), passing the wrong pointer to the cleanup function.
490+
491+
The bug only manifests when the first vector is parsed from JSON/TEXT
492+
(which uses sqlite3_free as cleanup) rather than BLOB (which uses noop).
493+
"""
494+
# Valid first vector as JSON text - this causes memory allocation
495+
# and sets cleanup to sqlite3_free
496+
valid_vector_json = "[1.0, 2.0, 3.0, 4.0]"
497+
498+
# Invalid second vector: 5 bytes, not divisible by 4 (sizeof float32)
499+
# This will fail in fvec_from_value with "invalid float32 vector BLOB length"
500+
invalid_vector = b"\x01\x02\x03\x04\x05"
501+
502+
with pytest.raises(sqlite3.OperationalError, match=r"^Error reading 2nd vector: invalid float32 vector BLOB length\. Must be divisible by 4, found 5$"):
503+
db.execute(
504+
"select vec_distance_cosine(?, ?)",
505+
[valid_vector_json, invalid_vector]
506+
).fetchone()
507+
483508
def test_vec_distance_hamming():
484509
vec_distance_hamming = lambda *args: db.execute(
485510
"select vec_distance_hamming(vec_bit(?), vec_bit(?))", args

0 commit comments

Comments
 (0)