Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -186,25 +186,47 @@ object ConfigurationPresets {
Platform.LINUX -> {
config.compilerArgs.set(asanCompilerArgs + commonLinuxCompilerArgs(version))

val libasan = PlatformUtils.locateLibasan(compiler)
val asanLinkerArgs = if (libasan != null) {
listOf(
"-L${File(libasan).parent}",
"-lasan",
"-lubsan",
val isClang = PlatformUtils.isClangCompiler(compiler)
val ldPreloadLib: String?
val baseLinkerArgs: List<String>
val asanLinkerArgs: List<String>

if (isClang) {
// With clang, ASan/UBSan symbols in the shared library are resolved at runtime
// by the full LLVM runtime (libclang_rt.asan-x86_64.so) loaded via LD_PRELOAD.
// At link time, clang adds only asan_static stubs (weak trampolines without strong
// definitions), so -Wl,-z,defs must be omitted — it would fail on unresolved
// ASan/UBSan symbols. Explicitly linking GCC's -lasan/-lubsan is also wrong:
// GCC's libubsan lacks LLVM-specific symbols (e.g. __ubsan_handle_function_type_mismatch_abort).
ldPreloadLib = PlatformUtils.locateClangRtAsan(compiler)
baseLinkerArgs = commonLinuxLinkerArgs().filter { it != "-Wl,-z,defs" }
asanLinkerArgs = listOf(
"-fsanitize=address",
"-fsanitize=undefined",
"-fno-omit-frame-pointer"
)
} else {
emptyList()
ldPreloadLib = PlatformUtils.locateLibasan(compiler)
baseLinkerArgs = commonLinuxLinkerArgs()
asanLinkerArgs = if (ldPreloadLib != null) {
listOf(
"-L${File(ldPreloadLib).parent}",
"-lasan",
"-lubsan",
"-fsanitize=address",
"-fsanitize=undefined",
"-fno-omit-frame-pointer"
)
} else {
emptyList()
}
}

config.linkerArgs.set(commonLinuxLinkerArgs() + asanLinkerArgs)
config.linkerArgs.set(baseLinkerArgs + asanLinkerArgs)

if (libasan != null) {
if (ldPreloadLib != null) {
config.testEnvironment.apply {
put("LD_PRELOAD", libasan)
put("LD_PRELOAD", ldPreloadLib)
put("ASAN_OPTIONS", "allocator_may_return_null=1:unwind_abort_on_malloc=1:use_sigaltstack=0:detect_stack_use_after_return=0:handle_segv=0:halt_on_error=0:abort_on_error=0:print_stacktrace=1:symbolize=1:log_path=/tmp/asan_%p.log:suppressions=$rootDir/gradle/sanitizers/asan.supp")
put("UBSAN_OPTIONS", "halt_on_error=0:abort_on_error=0:print_stacktrace=1:log_path=/tmp/ubsan_%p.log:suppressions=$rootDir/gradle/sanitizers/ubsan.supp")
put("LSAN_OPTIONS", "detect_leaks=0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,33 @@ object PlatformUtils {

fun locateLibtsan(compiler: String = "gcc"): String? = locateLibrary("libtsan", compiler)

fun isClangCompiler(compiler: String): Boolean {
return File(compiler).name.startsWith("clang")
}

/**
* Locate LLVM's ASan shared library (libclang_rt.asan-*.so) for use with clang.
* Returns null if the compiler is not clang or the library cannot be found.
* This library contains both ASan and UBSan symbols needed for LD_PRELOAD.
*/
fun locateClangRtAsan(compiler: String): String? {
if (!isClangCompiler(compiler)) return null
return try {
val process = ProcessBuilder(compiler, "--print-resource-dir")
.redirectErrorStream(true)
.start()
val resourceDir = process.inputStream.bufferedReader().readText().trim()
process.waitFor()
if (process.exitValue() != 0) return null

File("$resourceDir/lib/linux").listFiles()
?.firstOrNull { it.name.matches(Regex("libclang_rt\\.asan-.*\\.so")) }
?.absolutePath
} catch (e: Exception) {
null
}
}

fun checkFuzzerSupport(): Boolean {
return try {
val testFile = createTempFile("fuzzer_check", ".cpp")
Expand All @@ -155,7 +182,12 @@ object PlatformUtils {
}

fun hasAsan(compiler: String = "gcc"): Boolean {
return !isMusl() && locateLibasan(compiler) != null
if (isMusl()) return false
return if (isClangCompiler(compiler)) {
locateClangRtAsan(compiler) != null
} else {
locateLibasan(compiler) != null
}
}

fun hasTsan(compiler: String = "gcc"): Boolean {
Expand Down
Loading
Loading