Reject IVF binary quantizer when dimensions not divisible by 8

The binary quantizer uses D/8 for buffer sizes and memset, which
truncates for non-multiple-of-8 dimensions, causing OOB writes.
Rather than using ceiling division, enforce the constraint at
table creation time with a clear parse error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Garcia 2026-03-31 14:51:27 -07:00
parent 5e4c557f93
commit 4bee88384b
2 changed files with 20 additions and 0 deletions

View file

@ -3074,6 +3074,9 @@ int vec0_parse_vector_column(const char *source, int source_length,
if (rc != SQLITE_OK) { if (rc != SQLITE_OK) {
return SQLITE_ERROR; return SQLITE_ERROR;
} }
if (ivfConfig.quantizer == VEC0_IVF_QUANTIZER_BINARY && (dimensions % 8) != 0) {
return SQLITE_ERROR;
}
#else #else
return SQLITE_ERROR; // IVF not compiled in return SQLITE_ERROR; // IVF not compiled in
#endif #endif

View file

@ -253,3 +253,20 @@ def test_ivf_quantized_delete(db):
db.execute("DELETE FROM t WHERE rowid = 5") db.execute("DELETE FROM t WHERE rowid = 5")
# _ivf_vectors should have 9 rows # _ivf_vectors should have 9 rows
assert db.execute("SELECT count(*) FROM t_ivf_vectors00").fetchone()[0] == 9 assert db.execute("SELECT count(*) FROM t_ivf_vectors00").fetchone()[0] == 9
def test_ivf_binary_rejects_non_multiple_of_8_dims(db):
"""Binary quantizer requires dimensions divisible by 8."""
with pytest.raises(sqlite3.OperationalError):
db.execute(
"CREATE VIRTUAL TABLE t USING vec0("
" v float[12] indexed by ivf(quantizer=binary)"
")"
)
# Dimensions divisible by 8 should work
db.execute(
"CREATE VIRTUAL TABLE t2 USING vec0("
" v float[16] indexed by ivf(quantizer=binary)"
")"
)