Skip to content

Commit 5afc337

Browse files
committed
fix(build): strip explicit asan -l flags from gtest executable link
clang -fsanitize=address on an executable statically embeds the full ASan runtime via --whole-archive libclang_rt.asan*.a. Adding an explicit -lclang_rt.asan / -lasan on top creates a second dynamic NEEDED entry, causing two __asan_init calls and 'incompatible ASan runtimes' at startup. Shared library builds legitimately need the explicit -l to satisfy -z defs. Executables do not — clang handles the runtime automatically.
1 parent 01e3d25 commit 5afc337

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

build-logic/conventions/src/main/kotlin/com/datadoghq/native/gtest/GtestTaskBuilder.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,14 @@ class GtestTaskBuilder(
104104
}
105105

106106
private fun buildLinkTask(compileTask: TaskProvider<NativeCompileTask>): TaskProvider<NativeLinkExecutableTask> {
107-
val linkerArgs = config.linkerArgs.get()
107+
// For executables, clang's -fsanitize=address statically embeds the full
108+
// ASan runtime (--whole-archive libclang_rt.asan*.a). Adding an explicit
109+
// -lclang_rt.asan or -lasan on top produces a second dynamic NEEDED entry,
110+
// which triggers "incompatible ASan runtimes" at startup (two __asan_init
111+
// calls). Strip the explicit sanitizer -l/-L/-rpath flags here so the
112+
// executable relies solely on clang's automatic static embedding.
113+
val sanitizerLibPattern = Regex("^(-lasan|-lubsan|-lclang_rt\\.asan.*|-lclang_rt\\.ubsan.*|-L.*/clang.*/|-Wl,-rpath,.*/clang.*/)")
114+
val linkerArgs = config.linkerArgs.get().filter { !sanitizerLibPattern.containsMatchIn(it) }
108115
val objDir = project.file("${project.layout.buildDirectory.get()}/obj/gtest/${config.name}/$testName")
109116
val binary = project.file("${project.layout.buildDirectory.get()}/bin/gtest/${config.name}_$testName/$testName")
110117

0 commit comments

Comments
 (0)