Fuzz #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Fuzz" | |
| on: | |
| push: | |
| branches: [main] | |
| schedule: | |
| # Nightly at 2am UTC for longer fuzzing sessions | |
| - cron: "0 2 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| duration: | |
| description: "Fuzz duration per target (seconds)" | |
| default: "60" | |
| permissions: | |
| contents: read | |
| jobs: | |
| fuzz-linux: | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install LLVM 18 | |
| run: | | |
| wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- 18 | |
| echo "FUZZ_CC=clang-18" >> $GITHUB_ENV | |
| - run: ./scripts/vendor.sh | |
| - name: Generate sqlite-vec.h | |
| run: make sqlite-vec.h | |
| - name: Build fuzz targets | |
| run: make -C tests/fuzz all FUZZ_CC=$FUZZ_CC FUZZ_LDFLAGS= | |
| - name: Run fuzz targets | |
| run: | | |
| DURATION=${{ github.event.inputs.duration || '60' }} | |
| EXIT_CODE=0 | |
| for target in tests/fuzz/targets/*; do | |
| [ -f "$target" ] && [ -x "$target" ] || continue | |
| name=$(basename "$target") | |
| echo "::group::Fuzzing $name ($DURATION seconds)" | |
| corpus="tests/fuzz/corpus/$name" | |
| mkdir -p "$corpus" | |
| dict="tests/fuzz/${name//_/-}.dict" | |
| dict_flag="" | |
| [ -f "$dict" ] && dict_flag="-dict=$dict" | |
| if ! ASAN_OPTIONS=detect_leaks=1 "$target" $dict_flag \ | |
| -max_total_time="$DURATION" "$corpus" 2>&1; then | |
| echo "::error::Fuzz target $name found a crash!" | |
| EXIT_CODE=1 | |
| fi | |
| echo "::endgroup::" | |
| done | |
| exit $EXIT_CODE | |
| - name: Upload crash artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-crashes-linux | |
| path: | | |
| crash-* | |
| leak-* | |
| timeout-* | |
| fuzz-macos: | |
| runs-on: macos-14 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Use Apple's Xcode clang (avoids Homebrew LLVM libc++ ABI issues | |
| # with __ZnwmSt19__type_descriptor_t on macOS 14). | |
| - run: ./scripts/vendor.sh | |
| - name: Generate sqlite-vec.h | |
| run: make sqlite-vec.h | |
| - name: Build fuzz targets | |
| run: | | |
| SDK=$(xcrun --sdk macosx --show-sdk-path) | |
| make -C tests/fuzz all \ | |
| FUZZ_CC=$(xcrun -f clang) \ | |
| FUZZ_LDFLAGS="-isysroot $SDK" | |
| - name: Run fuzz targets | |
| run: | | |
| DURATION=${{ github.event.inputs.duration || '60' }} | |
| EXIT_CODE=0 | |
| for target in tests/fuzz/targets/*; do | |
| [ -f "$target" ] && [ -x "$target" ] || continue | |
| name=$(basename "$target") | |
| echo "::group::Fuzzing $name ($DURATION seconds)" | |
| corpus="tests/fuzz/corpus/$name" | |
| mkdir -p "$corpus" | |
| dict="tests/fuzz/${name//_/-}.dict" | |
| dict_flag="" | |
| [ -f "$dict" ] && dict_flag="-dict=$dict" | |
| if ! "$target" $dict_flag \ | |
| -max_total_time="$DURATION" "$corpus" 2>&1; then | |
| echo "::error::Fuzz target $name found a crash!" | |
| EXIT_CODE=1 | |
| fi | |
| echo "::endgroup::" | |
| done | |
| exit $EXIT_CODE | |
| - name: Upload crash artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-crashes-macos | |
| path: | | |
| crash-* | |
| leak-* | |
| timeout-* | |
| fuzz-windows: | |
| # Best-effort: libFuzzer works on Windows via LLVM but ASAN/UBSAN | |
| # support is less reliable. Leak detection is not available. | |
| runs-on: windows-2022 | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install LLVM | |
| run: choco install llvm -y | |
| - run: bash ./scripts/vendor.sh | |
| shell: bash | |
| - name: Generate sqlite-vec.h | |
| shell: bash | |
| run: make sqlite-vec.h | |
| - name: Build fuzz targets | |
| shell: bash | |
| run: | | |
| export PATH="/c/Program Files/LLVM/bin:$PATH" | |
| cd tests/fuzz | |
| mkdir -p targets | |
| for src in *.c; do | |
| name="${src%.c}" | |
| target_name="${name//-/_}" | |
| echo "Building $target_name from $src" | |
| clang -fsanitize=address,fuzzer \ | |
| -I ../../ -I ../../vendor -DSQLITE_CORE -g \ | |
| ../../vendor/sqlite3.c ../../sqlite-vec.c \ | |
| "$src" -o "targets/${target_name}.exe" || { | |
| echo "Warning: failed to build $target_name (best-effort)" | |
| } | |
| done | |
| - name: Run fuzz targets | |
| shell: bash | |
| run: | | |
| export PATH="/c/Program Files/LLVM/bin:$PATH" | |
| DURATION=${{ github.event.inputs.duration || '60' }} | |
| for target in tests/fuzz/targets/*.exe; do | |
| [ -f "$target" ] || continue | |
| name=$(basename "$target" .exe) | |
| echo "=== Fuzzing $name ($DURATION seconds) ===" | |
| corpus="tests/fuzz/corpus/$name" | |
| mkdir -p "$corpus" | |
| "$target" -max_total_time="$DURATION" "$corpus" 2>&1 || { | |
| echo "Warning: $name found an issue or failed" | |
| } | |
| done | |
| - name: Upload crash artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-crashes-windows | |
| path: | | |
| tests/fuzz/crash-* | |
| tests/fuzz/leak-* |