From 1b53b942e0c0d6e110ff3c5975ec5702018b9b31 Mon Sep 17 00:00:00 2001 From: Alex Garcia Date: Tue, 3 Mar 2026 08:36:59 -0800 Subject: [PATCH] Fix remaining fuzzer issues: leaks, UBSAN NaN, macOS LLVM version - fuzz.yaml: switch macOS to llvm@18 (latest LLVM uses typed allocation C++ ABI symbols not available on macOS 14 runner's system libc++) - sqlite-vec.c: fix NaN input in vec_quantize_int8 by using !(val <= X) comparisons which evaluate to true for NaN, ensuring the clamp fires - sqlite-vec.c: free pzErrMsg in vec_eachFilter error path (was leaking the error string returned by vector_from_value) - sqlite-vec.c: add sqlite3_free(pNew) to vec0_init error path; vec0_free frees the contents but not the struct itself, mirroring vec0Disconnect - sqlite-vec.c: free knn_data in vec0Filter_knn cleanup when rc != SQLITE_OK; on error the cursor's knn_data field is never set so it would not be freed by the cursor teardown path Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/fuzz.yaml | 10 +++++----- sqlite-vec.c | 10 ++++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/fuzz.yaml b/.github/workflows/fuzz.yaml index d3f2fad..0602072 100644 --- a/.github/workflows/fuzz.yaml +++ b/.github/workflows/fuzz.yaml @@ -63,20 +63,20 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 - - name: Install LLVM - run: brew install llvm + - name: Install LLVM 18 + run: brew install llvm@18 - run: ./scripts/vendor.sh - name: Generate sqlite-vec.h run: make sqlite-vec.h - name: Build fuzz targets run: | - LLVM=/opt/homebrew/opt/llvm + LLVM=/opt/homebrew/opt/llvm@18 make -C tests/fuzz all \ FUZZ_CC=$LLVM/bin/clang \ - FUZZ_LDFLAGS="-Wl,-ld_classic -L$LLVM/lib/c++ -Wl,-rpath,$LLVM/lib/c++" + FUZZ_LDFLAGS="-Wl,-ld_classic" - name: Run fuzz targets env: - DYLD_LIBRARY_PATH: "/opt/homebrew/opt/llvm/lib/c++:${{ env.DYLD_LIBRARY_PATH }}" + DYLD_LIBRARY_PATH: "/opt/homebrew/opt/llvm@18/lib/c++:${{ env.DYLD_LIBRARY_PATH }}" run: | DURATION=${{ github.event.inputs.duration || '60' }} EXIT_CODE=0 diff --git a/sqlite-vec.c b/sqlite-vec.c index 1fa781e..45fbec9 100644 --- a/sqlite-vec.c +++ b/sqlite-vec.c @@ -1465,8 +1465,8 @@ static void vec_quantize_int8(sqlite3_context *context, int argc, f32 step = (1.0 - (-1.0)) / 255; for (size_t i = 0; i < dimensions; i++) { double val = ((srcVector[i] - (-1.0)) / step) - 128; - if (val > 127.0) val = 127.0; - if (val < -128.0) val = -128.0; + if (!(val <= 127.0)) val = 127.0; /* also clamps NaN */ + if (!(val >= -128.0)) val = -128.0; out[i] = (i8)val; } @@ -2577,6 +2577,7 @@ static int vec_eachFilter(sqlite3_vtab_cursor *pVtabCursor, int idxNum, int rc = vector_from_value(argv[0], &pCur->vector, &pCur->dimensions, &pCur->vector_type, &pCur->cleanup, &pzErrMsg); if (rc != SQLITE_OK) { + sqlite3_free(pzErrMsg); return SQLITE_ERROR; } pCur->iRowid = 0; @@ -5202,6 +5203,7 @@ static int vec0_init(sqlite3 *db, void *pAux, int argc, const char *const *argv, error: vec0_free(pNew); + sqlite3_free(pNew); return SQLITE_ERROR; } @@ -7259,6 +7261,10 @@ cleanup: sqlite3_free(aMetadataIn); + if (rc != SQLITE_OK) { + sqlite3_free(knn_data); + } + return rc; }