@@ -67,10 +67,11 @@ CFLAGS_TEST = $(CFLAGS_COMMON) -g -O1 $(SANITIZE)
6767CXXFLAGS_TEST = $(CXXFLAGS_COMMON) -g -O1 $(SANITIZE)
6868
6969# TSan (can't combine with ASan)
70+ TSAN_SANITIZE = -fsanitize=thread -fno-omit-frame-pointer
7071CFLAGS_TSAN = $(CFLAGS_COMMON) -g -O1 \
71- -fsanitize=thread -fno-omit-frame-pointer
72+ $(TSAN_SANITIZE)
7273CXXFLAGS_TSAN = $(CXXFLAGS_COMMON) -g -O1 \
73- -fsanitize=thread -fno-omit-frame-pointer
74+ $(TSAN_SANITIZE)
7475
7576# Windows needs ws2_32 (Winsock), psapi (GetProcessMemoryInfo), shell32
7677# (CommandLineToArgvW — the UTF-8 argv path in main.c, #423/#20), and
8990
9091LDFLAGS = -lm -lstdc++ -lpthread -lz $(WIN32_LIBS) $(STATIC_FLAGS)
9192LDFLAGS_TEST = -lm -lstdc++ -lpthread -lz $(SANITIZE) $(WIN32_LIBS)
92- LDFLAGS_TSAN = -lm -lstdc++ -lpthread -lz -fsanitize=thread $(WIN32_LIBS)
93+ LDFLAGS_TSAN = -lm -lstdc++ -lpthread -lz $(TSAN_SANITIZE) $(WIN32_LIBS)
9394
9495# ── Source files ─────────────────────────────────────────────────
9596
@@ -485,13 +486,17 @@ GRAMMAR_CFLAGS = -std=c11 -D_DEFAULT_SOURCE -O2 -w -I$(CBM_DIR) -I$(TS_INCLUDE)
485486GRAMMAR_CFLAGS_TEST = -std=c11 -D_DEFAULT_SOURCE -g -O1 -w -I$(CBM_DIR) -I$(TS_INCLUDE) -I$(TS_SRC) \
486487 $(SANITIZE)
487488GRAMMAR_CFLAGS_TSAN = -std=c11 -D_DEFAULT_SOURCE -g -O1 -w -I$(CBM_DIR) -I$(TS_INCLUDE) -I$(TS_SRC) \
488- -fsanitize=thread -fno-omit-frame-pointer
489+ $(TSAN_SANITIZE)
489490
490491# Object files for grammars + ts_runtime + lsp_all + preprocessor
491492GRAMMAR_OBJS_TEST = $(patsubst $(CBM_DIR)/%.c,$(BUILD_DIR)/%.o,$(GRAMMAR_SRCS))
492493TS_RUNTIME_OBJ_TEST = $(BUILD_DIR)/ts_runtime.o
493494LSP_OBJ_TEST = $(BUILD_DIR)/lsp_all.o
494495PP_OBJ_TEST = $(BUILD_DIR)/preprocessor.o
496+ GRAMMAR_OBJS_TSAN = $(patsubst $(CBM_DIR)/%.c,$(BUILD_DIR)/tsan_%.o,$(GRAMMAR_SRCS))
497+ TS_RUNTIME_OBJ_TSAN = $(BUILD_DIR)/tsan_ts_runtime.o
498+ LSP_OBJ_TSAN = $(BUILD_DIR)/tsan_lsp_all.o
499+ PP_OBJ_TSAN = $(BUILD_DIR)/tsan_preprocessor.o
495500
496501# ── Targets ──────────────────────────────────────────────────────
497502
@@ -522,60 +527,94 @@ $(BUILD_DIR)/lsp_all.o: $(LSP_UNITY_DEPS) | $(BUILD_DIR)
522527$(BUILD_DIR)/preprocessor.o: $(CBM_DIR)/preprocessor.cpp | $(BUILD_DIR)
523528 $(CXX) $(CXXFLAGS_TEST) -w -I$(CBM_DIR)/vendored -c -o $@ $<
524529
530+ $(BUILD_DIR)/tsan_%.o: $(CBM_DIR)/%.c | $(BUILD_DIR)
531+ $(CC) $(GRAMMAR_CFLAGS_TSAN) -c -o $@ $<
532+
533+ $(BUILD_DIR)/tsan_ts_runtime.o: $(CBM_DIR)/ts_runtime.c | $(BUILD_DIR)
534+ $(CC) $(GRAMMAR_CFLAGS_TSAN) -c -o $@ $<
535+
536+ $(BUILD_DIR)/tsan_lsp_all.o: $(LSP_UNITY_DEPS) | $(BUILD_DIR)
537+ $(CC) $(GRAMMAR_CFLAGS_TSAN) -c -o $@ $<
538+
539+ $(BUILD_DIR)/tsan_preprocessor.o: $(CBM_DIR)/preprocessor.cpp | $(BUILD_DIR)
540+ $(CXX) $(CXXFLAGS_TSAN) -w -I$(CBM_DIR)/vendored -c -o $@ $<
541+
525542# ── Full test binary ─────────────────────────────────────────────
526543
527544# mimalloc object files
528545MIMALLOC_OBJ_TEST = $(BUILD_DIR)/mimalloc.o
546+ MIMALLOC_OBJ_TSAN = $(BUILD_DIR)/tsan_mimalloc.o
529547MIMALLOC_OBJ_PROD = $(BUILD_DIR)/prod_mimalloc.o
530548
531549$(BUILD_DIR)/mimalloc.o: $(MIMALLOC_SRC) | $(BUILD_DIR)
532550 $(CC) $(MIMALLOC_CFLAGS_TEST) -c -o $@ $<
533551
552+ $(BUILD_DIR)/tsan_mimalloc.o: $(MIMALLOC_SRC) | $(BUILD_DIR)
553+ $(CC) $(MIMALLOC_CFLAGS_TEST) $(TSAN_SANITIZE) -c -o $@ $<
554+
534555$(BUILD_DIR)/prod_mimalloc.o: $(MIMALLOC_SRC) | $(BUILD_DIR)
535556 $(CC) $(MIMALLOC_CFLAGS) -c -o $@ $<
536557
537558# sqlite3 object files (vendored amalgamation)
538559SQLITE3_OBJ_TEST = $(BUILD_DIR)/sqlite3.o
560+ SQLITE3_OBJ_TSAN = $(BUILD_DIR)/tsan_sqlite3.o
539561SQLITE3_OBJ_PROD = $(BUILD_DIR)/prod_sqlite3.o
540562
541563$(BUILD_DIR)/sqlite3.o: $(SQLITE3_SRC) | $(BUILD_DIR)
542564 $(CC) $(SQLITE3_CFLAGS_TEST) $(SANITIZE) -c -o $@ $<
543565
566+ $(BUILD_DIR)/tsan_sqlite3.o: $(SQLITE3_SRC) | $(BUILD_DIR)
567+ $(CC) $(SQLITE3_CFLAGS_TEST) $(TSAN_SANITIZE) -c -o $@ $<
568+
544569$(BUILD_DIR)/prod_sqlite3.o: $(SQLITE3_SRC) | $(BUILD_DIR)
545570 $(CC) $(SQLITE3_CFLAGS) -c -o $@ $<
546571
547572# TRE regex (only compiled on Windows — POSIX uses system <regex.h>)
548573TRE_OBJ_TEST :=
574+ TRE_OBJ_TSAN :=
549575TRE_OBJ_PROD :=
550576ifeq ($(IS_MINGW),yes)
551577TRE_OBJ_TEST = $(BUILD_DIR)/tre.o
578+ TRE_OBJ_TSAN = $(BUILD_DIR)/tsan_tre.o
552579TRE_OBJ_PROD = $(BUILD_DIR)/prod_tre.o
553580
554581$(BUILD_DIR)/tre.o: $(TRE_SRC) | $(BUILD_DIR)
555582 $(CC) $(TRE_CFLAGS) $(SANITIZE) -fno-sanitize=alignment -c -o $@ $<
556583
584+ $(BUILD_DIR)/tsan_tre.o: $(TRE_SRC) | $(BUILD_DIR)
585+ $(CC) $(TRE_CFLAGS) $(TSAN_SANITIZE) -c -o $@ $<
586+
557587$(BUILD_DIR)/prod_tre.o: $(TRE_SRC) | $(BUILD_DIR)
558588 $(CC) $(TRE_CFLAGS) -O2 -c -o $@ $<
559589endif
560590
561591# Vendored LZ4 (test build)
562592LZ4_OBJ_TEST = $(BUILD_DIR)/test_lz4.o $(BUILD_DIR)/test_lz4hc.o
593+ LZ4_OBJ_TSAN = $(BUILD_DIR)/tsan_lz4.o $(BUILD_DIR)/tsan_lz4hc.o
563594$(BUILD_DIR)/test_lz4.o: $(CBM_DIR)/vendored/lz4/lz4.c | $(BUILD_DIR)
564595 $(CC) -std=c11 -D_DEFAULT_SOURCE -g -O1 $(SANITIZE) -w -I$(CBM_DIR) -c -o $@ $<
565596$(BUILD_DIR)/test_lz4hc.o: $(CBM_DIR)/vendored/lz4/lz4hc.c | $(BUILD_DIR)
566597 $(CC) -std=c11 -D_DEFAULT_SOURCE -g -O1 $(SANITIZE) -w -I$(CBM_DIR)/vendored/lz4 -c -o $@ $<
598+ $(BUILD_DIR)/tsan_lz4.o: $(CBM_DIR)/vendored/lz4/lz4.c | $(BUILD_DIR)
599+ $(CC) -std=c11 -D_DEFAULT_SOURCE -g -O1 $(TSAN_SANITIZE) -w -I$(CBM_DIR) -c -o $@ $<
600+ $(BUILD_DIR)/tsan_lz4hc.o: $(CBM_DIR)/vendored/lz4/lz4hc.c | $(BUILD_DIR)
601+ $(CC) -std=c11 -D_DEFAULT_SOURCE -g -O1 $(TSAN_SANITIZE) -w -I$(CBM_DIR)/vendored/lz4 -c -o $@ $<
567602
568603# Vendored zstd (test build)
569604ZSTD_OBJ_TEST = $(BUILD_DIR)/test_zstd.o
605+ ZSTD_OBJ_TSAN = $(BUILD_DIR)/tsan_zstd.o
570606$(BUILD_DIR)/test_zstd.o: $(CBM_DIR)/vendored/zstd/zstd.c | $(BUILD_DIR)
571607 $(CC) -std=c11 -D_DEFAULT_SOURCE -g -O1 $(SANITIZE) -w -I$(CBM_DIR)/vendored/zstd -c -o $@ $<
608+ $(BUILD_DIR)/tsan_zstd.o: $(CBM_DIR)/vendored/zstd/zstd.c | $(BUILD_DIR)
609+ $(CC) -std=c11 -D_DEFAULT_SOURCE -g -O1 $(TSAN_SANITIZE) -w -I$(CBM_DIR)/vendored/zstd -c -o $@ $<
572610
573611# nomic-embed-code pretrained vector blob
574612UNIXCODER_OBJ = $(BUILD_DIR)/unixcoder_blob.o
575613$(UNIXCODER_OBJ): $(UNIXCODER_BLOB_SRC) vendored/nomic/code_vectors.bin | $(BUILD_DIR)
576614 $(CC) -c -o $@ $<
577615
578616OBJS_VENDORED_TEST = $(MIMALLOC_OBJ_TEST) $(SQLITE3_OBJ_TEST) $(TRE_OBJ_TEST) $(GRAMMAR_OBJS_TEST) $(TS_RUNTIME_OBJ_TEST) $(LSP_OBJ_TEST) $(PP_OBJ_TEST) $(LZ4_OBJ_TEST) $(ZSTD_OBJ_TEST) $(UNIXCODER_OBJ)
617+ OBJS_VENDORED_TSAN = $(MIMALLOC_OBJ_TSAN) $(SQLITE3_OBJ_TSAN) $(TRE_OBJ_TSAN) $(GRAMMAR_OBJS_TSAN) $(TS_RUNTIME_OBJ_TSAN) $(LSP_OBJ_TSAN) $(PP_OBJ_TSAN) $(LZ4_OBJ_TSAN) $(ZSTD_OBJ_TSAN) $(UNIXCODER_OBJ)
579618
580619$(BUILD_DIR)/test-runner: $(ALL_TEST_SRCS) $(PROD_SRCS) $(EXTRACTION_SRCS) $(AC_LZ4_SRCS) $(ZSTD_SRCS) $(SQLITE_WRITER_SRC) $(OBJS_VENDORED_TEST) | $(BUILD_DIR)
581620 $(CC) $(CFLAGS_TEST) -Itests -Itests/repro -o $@ \
@@ -603,8 +642,18 @@ test-repro: $(BUILD_DIR)/test-repro-runner
603642
604643# ── TSan full test ───────────────────────────────────────────────
605644
606- test-tsan:
607- @echo "TSan not yet wired for full extraction tests"
645+ TEST_TSAN_SUITES ?= mem slab_alloc parallel
646+ TSAN_OPTIONS ?= halt_on_error=1
647+
648+ $(BUILD_DIR)/test-runner-tsan: $(ALL_TEST_SRCS) $(PROD_SRCS) $(EXTRACTION_SRCS) $(AC_LZ4_SRCS) $(ZSTD_SRCS) $(SQLITE_WRITER_SRC) $(OBJS_VENDORED_TSAN) | $(BUILD_DIR)
649+ $(CC) $(CFLAGS_TSAN) -Itests -Itests/repro -o $@ \
650+ $(ALL_TEST_SRCS) $(PROD_SRCS) \
651+ $(EXTRACTION_SRCS) $(AC_LZ4_SRCS) $(ZSTD_SRCS) $(SQLITE_WRITER_SRC) \
652+ $(OBJS_VENDORED_TSAN) \
653+ $(LDFLAGS_TSAN)
654+
655+ test-tsan: $(BUILD_DIR)/test-runner-tsan
656+ cd $(CURDIR) && TSAN_OPTIONS="$(TSAN_OPTIONS)" $(BUILD_DIR)/test-runner-tsan $(TEST_TSAN_SUITES)
608657
609658# ── Production binary ────────────────────────────────────────────
610659
0 commit comments