From cd338a7a435fd04eafcfcb5892b61341efa80537 Mon Sep 17 00:00:00 2001 From: Will Lillis Date: Mon, 25 May 2026 02:46:49 -0400 Subject: [PATCH] fix(loader): skip --no-undefined for sanitizer grammar builds Compiling a grammar with `-fsanitize=address` (or any other sanitizer) emits a module constructor in the parser object file that references runtime symbols like `__asan_init`. These runtime-resolved symbols are incompatible with `-Wl,--no-undefined`, which breaking sanitized test runs on clang. (gcc happens to paper over this by auto-linking libasan into the .so) To fix, detect `-fsanitize=` in the compile flags and omit `--no-undefined` in that case. --- crates/loader/src/loader.rs | 10 +++++++++- docs/src/6-contributing.md | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/loader/src/loader.rs b/crates/loader/src/loader.rs index 05304277d..2a485d81b 100755 --- a/crates/loader/src/loader.rs +++ b/crates/loader/src/loader.rs @@ -1306,7 +1306,15 @@ impl Loader { command.arg("-UTREE_SITTER_REUSE_ALLOCATOR"); } else { command.arg("-shared"); - command.arg("-Wl,--no-undefined"); + // Sanitizer builds reference runtime symbols that `--no-undefined` + // would reject at link time. + let sanitizing = compiler + .args() + .iter() + .any(|a| a.to_str().is_some_and(|s| s.starts_with("-fsanitize="))); + if !sanitizing { + command.arg("-Wl,--no-undefined"); + } #[cfg(target_os = "openbsd")] command.arg("-lc"); } diff --git a/docs/src/6-contributing.md b/docs/src/6-contributing.md index 36173d6c1..e09ceec7c 100644 --- a/docs/src/6-contributing.md +++ b/docs/src/6-contributing.md @@ -184,6 +184,27 @@ You can enable these helpers by importing them: (lldb) command script import /path/to/tree-sitter/lib/lldb_pretty_printers/tree_sitter_types.py ``` +#### Sanitizers + +Tests can be run with AddressSanitizer or UndefinedBehaviorSanitizer to track down memory or UB issues in the C library +or in grammar parsers. The standard recipe is + +```sh +CFLAGS=-fsanitize=address \ +RUSTFLAGS="-lasan --cfg sanitizing" \ +ASAN_OPTIONS=verify_asan_link_order=0 \ +cargo test +``` + +Swap `address` -> `undefined` (and `-lasan` -> `-lubsan`) for UBSAN, or combine them with `-fsanitize=undefined,address` +and both `-l` flags. + +If the loader detects `-fsanitize=` in the compile flags, `-Wl,--no-undefined` is dropped from the grammar link step. This +lets the grammar's sanitizer runtime symbols be resolved at runtime rather than be rejected at link time. + +If you flip between sanitizer and non-sanitizer runs you may pick up cached parser builds from the previous mode in `target/scratch/`. +Clear that directory to resolve any inconsistencies. + ## Published Packages The main [`tree-sitter/tree-sitter`][ts repo] repository contains the source code for