|
| 1 | +#!/bin/bash |
| 2 | +# |
| 3 | +# AddressSanitizer (ASan) and LeakSanitizer (LSan) test runner for sqlite-vec |
| 4 | +# Detects buffer overflows, use-after-free, double-free, and memory leaks. |
| 5 | +# |
| 6 | +# Usage: ./scripts/sanitizers-test.sh |
| 7 | +# Or: make test-asan |
| 8 | + |
| 9 | +set -euo pipefail |
| 10 | + |
| 11 | +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" |
| 12 | +ROOT_DIR="$(dirname "$SCRIPT_DIR")" |
| 13 | + |
| 14 | +# Colors for output |
| 15 | +RED='\033[0;31m' |
| 16 | +GREEN='\033[0;32m' |
| 17 | +YELLOW='\033[1;33m' |
| 18 | +BLUE='\033[0;34m' |
| 19 | +NC='\033[0m' # No Color |
| 20 | + |
| 21 | +# Only run on Linux (macOS has SIP issues with ASan) |
| 22 | +if [[ "$OSTYPE" != "linux-gnu"* ]]; then |
| 23 | + echo -e "${YELLOW}AddressSanitizer tests currently only supported on Linux.${NC}" |
| 24 | + echo -e "${YELLOW}macOS requires additional setup due to SIP restrictions.${NC}" |
| 25 | + exit 0 |
| 26 | +fi |
| 27 | + |
| 28 | +# Check for clang or gcc |
| 29 | +CC="${CC:-}" |
| 30 | +if [[ -z "$CC" ]]; then |
| 31 | + if command -v clang &>/dev/null; then |
| 32 | + CC=clang |
| 33 | + elif command -v gcc &>/dev/null; then |
| 34 | + CC=gcc |
| 35 | + else |
| 36 | + echo -e "${RED}Error: Neither clang nor gcc found. Install one to run ASan tests.${NC}" |
| 37 | + exit 1 |
| 38 | + fi |
| 39 | +fi |
| 40 | + |
| 41 | +echo -e "${BLUE}=== AddressSanitizer + LeakSanitizer Tests ===${NC}" |
| 42 | +echo "Using compiler: $CC" |
| 43 | + |
| 44 | +# Configuration |
| 45 | +OUTPUT_FILE="$ROOT_DIR/asan-output.log" |
| 46 | +MEMORY_TEST="$ROOT_DIR/dist/memory-test-asan" |
| 47 | + |
| 48 | +# ASan/LSan options |
| 49 | +export ASAN_OPTIONS="detect_leaks=1:halt_on_error=1:print_stats=1:check_initialization_order=1" |
| 50 | +export LSAN_OPTIONS="print_suppressions=0" |
| 51 | + |
| 52 | +# Clean previous output |
| 53 | +rm -f "$OUTPUT_FILE" |
| 54 | + |
| 55 | +# ASan compiler flags |
| 56 | +ASAN_CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -g -O1" |
| 57 | +ASAN_LDFLAGS="-fsanitize=address,undefined" |
| 58 | + |
| 59 | +# Build the ASan-instrumented memory test |
| 60 | +echo -e "\n${YELLOW}Building memory-test with AddressSanitizer...${NC}" |
| 61 | + |
| 62 | +$CC $ASAN_CFLAGS \ |
| 63 | + -fvisibility=hidden \ |
| 64 | + -I"$ROOT_DIR/vendor/" -I"$ROOT_DIR/" \ |
| 65 | + -DSQLITE_CORE \ |
| 66 | + -DSQLITE_VEC_STATIC \ |
| 67 | + -DSQLITE_THREADSAFE=0 \ |
| 68 | + "$ROOT_DIR/tests/memory-test.c" \ |
| 69 | + "$ROOT_DIR/sqlite-vec.c" \ |
| 70 | + "$ROOT_DIR/vendor/sqlite3.c" \ |
| 71 | + -o "$MEMORY_TEST" \ |
| 72 | + $ASAN_LDFLAGS -ldl -lm |
| 73 | + |
| 74 | +if [ ! -f "$MEMORY_TEST" ]; then |
| 75 | + echo -e "${RED}Error: ASan build failed. Binary not found at $MEMORY_TEST${NC}" |
| 76 | + exit 1 |
| 77 | +fi |
| 78 | +echo -e "${GREEN}ASan build complete${NC}" |
| 79 | + |
| 80 | +# Run the ASan-instrumented memory test |
| 81 | +echo -e "\n${YELLOW}Running memory tests with AddressSanitizer...${NC}" |
| 82 | + |
| 83 | +set +e |
| 84 | +"$MEMORY_TEST" 2>&1 | tee "$OUTPUT_FILE" |
| 85 | +TEST_EXIT=${PIPESTATUS[0]} |
| 86 | +set -e |
| 87 | + |
| 88 | +echo "" |
| 89 | + |
| 90 | +# Analyze output for ASan/LSan errors |
| 91 | +echo -e "${BLUE}=== Analyzing ASan/LSan output ===${NC}" |
| 92 | + |
| 93 | +RESULT=0 |
| 94 | + |
| 95 | +# Check for ASan errors |
| 96 | +if grep -q "ERROR: AddressSanitizer" "$OUTPUT_FILE"; then |
| 97 | + echo -e "${RED}FAIL: AddressSanitizer found errors:${NC}" |
| 98 | + grep -B 2 -A 20 "ERROR: AddressSanitizer" "$OUTPUT_FILE" | head -50 || true |
| 99 | + RESULT=1 |
| 100 | +fi |
| 101 | + |
| 102 | +# Check for LSan errors |
| 103 | +if grep -q "ERROR: LeakSanitizer" "$OUTPUT_FILE"; then |
| 104 | + echo -e "${RED}FAIL: LeakSanitizer found memory leaks:${NC}" |
| 105 | + grep -B 2 -A 30 "ERROR: LeakSanitizer" "$OUTPUT_FILE" | head -60 || true |
| 106 | + RESULT=1 |
| 107 | +fi |
| 108 | + |
| 109 | +# Check for undefined behavior |
| 110 | +if grep -q "runtime error:" "$OUTPUT_FILE"; then |
| 111 | + echo -e "${RED}FAIL: UndefinedBehaviorSanitizer found issues:${NC}" |
| 112 | + grep -B 2 -A 5 "runtime error:" "$OUTPUT_FILE" | head -30 || true |
| 113 | + RESULT=1 |
| 114 | +fi |
| 115 | + |
| 116 | +# Check test exit code |
| 117 | +if [[ "$TEST_EXIT" -ne 0 && "$RESULT" -eq 0 ]]; then |
| 118 | + echo -e "${RED}FAIL: Tests failed with exit code $TEST_EXIT${NC}" |
| 119 | + RESULT=1 |
| 120 | +fi |
| 121 | + |
| 122 | +if [[ "$RESULT" -eq 0 ]]; then |
| 123 | + echo -e "\n${GREEN}PASS: No memory errors detected${NC}" |
| 124 | + rm -f "$OUTPUT_FILE" |
| 125 | +else |
| 126 | + echo -e "\n${RED}Memory issues detected! See $OUTPUT_FILE for full details.${NC}" |
| 127 | +fi |
| 128 | + |
| 129 | +# Clean up ASan build artifacts |
| 130 | +echo -e "\n${YELLOW}Cleaning up ASan build...${NC}" |
| 131 | +rm -f "$MEMORY_TEST" |
| 132 | +echo -e "${GREEN}Cleanup complete${NC}" |
| 133 | + |
| 134 | +exit $RESULT |
0 commit comments