Skip to content

Commit 87ee799

Browse files
rkennkeclaude
andauthored
build-logic: link sanitizer runtime for the fuzzer shared lib (#646)
commonLinuxLinkerArgs() carries -Wl,-z,defs, which forbids undefined symbols in the output. The fuzzer objects are instrumented with -fsanitize=address,undefined and therefore reference __asan_*/__ubsan_*, but -fsanitize=address only links the sanitizer runtime into *executables*, not shared libraries. So the fuzzer .so ends up with undefined __asan_*/__ubsan_* and the link fails under -z defs on any box where the fuzzer config is active (clang with libFuzzer, non-musl). The asan config already solves this by linking the matching runtime explicitly via locateLibasan (-lclang_rt.asan-<arch> on clang, which also provides UBSan symbols; -lasan + -lubsan on gcc). Apply the same, already-proven treatment to configureFuzzer: thread the detected compiler through and add the runtime to the Linux linker args. CI never hit this because its publish/build path passes --exclude-task compileFuzzer and only assembles the release jar, so the fuzzer is never linked there. It only bites a local build that links all active configs (e.g. publishToMavenLocal on a clang box). The macOS branch is unchanged. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e22b8f9 commit 87ee799

1 file changed

Lines changed: 25 additions & 3 deletions

File tree

build-logic/conventions/src/main/kotlin/com/datadoghq/native/config/ConfigurationPresets.kt

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ object ConfigurationPresets {
5151
configureTsan(this, currentPlatform, currentArch, version, rootDir, compiler)
5252
}
5353
register("fuzzer") {
54-
configureFuzzer(this, currentPlatform, currentArch, version, rootDir)
54+
configureFuzzer(this, currentPlatform, currentArch, version, rootDir, compiler)
5555
}
5656
}
5757

@@ -313,7 +313,8 @@ object ConfigurationPresets {
313313
platform: Platform,
314314
architecture: Architecture,
315315
version: String,
316-
rootDir: File
316+
rootDir: File,
317+
compiler: String = "gcc"
317318
) {
318319
config.platform.set(platform)
319320
config.architecture.set(architecture)
@@ -339,7 +340,28 @@ object ConfigurationPresets {
339340
when (platform) {
340341
Platform.LINUX -> {
341342
config.compilerArgs.set(fuzzerCompilerArgs + commonLinuxCompilerArgs(version))
342-
config.linkerArgs.set(commonLinuxLinkerArgs() + fuzzerLinkerArgs)
343+
344+
// commonLinuxLinkerArgs() carries -Wl,-z,defs, which forbids the
345+
// undefined __asan_*/__ubsan_* symbols the instrumented objects
346+
// reference. -fsanitize=address only links the runtime into
347+
// executables, not shared libraries, so the fuzzer .so needs the
348+
// runtime linked explicitly — same treatment (and rationale) as the
349+
// asan config. On clang this resolves both __asan_* and __ubsan_*
350+
// from one clang_rt.asan runtime; on gcc it adds -lubsan.
351+
val libasan = PlatformUtils.locateLibasan(compiler)
352+
val fuzzerRuntimeArgs = if (libasan != null) {
353+
val asanLibDir = File(libasan).parent
354+
val asanLibName = File(libasan).nameWithoutExtension.removePrefix("lib")
355+
val ubsanLibs = if (asanLibName.startsWith("clang_rt")) emptyList()
356+
else listOf("-lubsan")
357+
listOf("-L$asanLibDir", "-l$asanLibName",
358+
"-Wl,-rpath,$asanLibDir") +
359+
ubsanLibs +
360+
fuzzerLinkerArgs
361+
} else {
362+
fuzzerLinkerArgs
363+
}
364+
config.linkerArgs.set(commonLinuxLinkerArgs() + fuzzerRuntimeArgs)
343365

344366
config.testEnvironment.apply {
345367
put("ASAN_OPTIONS", "allocator_may_return_null=1:detect_stack_use_after_return=0:handle_segv=0:abort_on_error=1:symbolize=1:suppressions=$rootDir/gradle/sanitizers/asan.supp")

0 commit comments

Comments
 (0)