diff --git a/CMakeLists.txt b/CMakeLists.txt index 85948552ad2..b2f9ecb9ec3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -766,21 +766,31 @@ function(copy_compilerrt_lib llvm_lib_name ldc_lib_name fixup_dylib) endif() endfunction() if (LDC_INSTALL_LLVM_RUNTIME_LIBS) + # Locate LLVM sanitizer runtime libraries, and copy them to our lib folder + # Note: libFuzzer is part of compiler-rt version >= 6.0, but was part of LLVM =< 5.0 + if(APPLE) copy_compilerrt_lib("darwin/libclang_rt.asan_osx_dynamic.dylib" "libldc_rt.asan_osx_dynamic.dylib" TRUE) + if(NOT (LDC_LLVM_VER LESS 600)) + copy_compilerrt_lib("darwin/libclang_rt.fuzzer_osx.a" "libldc_rt.fuzzer_osx.a" FALSE) + endif() elseif(UNIX) copy_compilerrt_lib("linux/libclang_rt.asan-x86_64.a" "libldc_rt.asan-x86_64.a" FALSE) + if(NOT (LDC_LLVM_VER LESS 600)) + copy_compilerrt_lib("linux/libclang_rt.fuzzer-x86_64.a" "libldc_rt.fuzzer-x86_64.a" FALSE) + endif() endif() - # Locate libFuzzer runtime library, and copy it to our lib folder - set(LLVM_LIBFUZZER_PATH ${LLVM_LIBRARY_DIRS}/libFuzzer.a) - if(EXISTS ${LLVM_LIBFUZZER_PATH}) - message(STATUS "Copying libFuzzer library: ${LLVM_LIBFUZZER_PATH} --> libFuzzer.a") - file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}) - configure_file(${LLVM_LIBFUZZER_PATH} ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/libFuzzer.a COPYONLY) - install(FILES ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/libFuzzer.a DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) - else() - message(STATUS "Not found: ${LLVM_LIBFUZZER_PATH}") + if(LDC_LLVM_VER LESS 600) + set(LLVM_LIBFUZZER_PATH ${LLVM_LIBRARY_DIRS}/libFuzzer.a) + if(EXISTS ${LLVM_LIBFUZZER_PATH}) + message(STATUS "Copying libFuzzer library: ${LLVM_LIBFUZZER_PATH} --> libFuzzer.a") + file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}) + configure_file(${LLVM_LIBFUZZER_PATH} ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/libFuzzer.a COPYONLY) + install(FILES ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/libFuzzer.a DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) + else() + message(STATUS "Not found: ${LLVM_LIBFUZZER_PATH}") + endif() endif() endif() diff --git a/driver/linker-gcc.cpp b/driver/linker-gcc.cpp index 33d59831e76..8e2a77ca9b2 100644 --- a/driver/linker-gcc.cpp +++ b/driver/linker-gcc.cpp @@ -180,58 +180,38 @@ void ArgsBuilder::addLTOLinkFlags() { ////////////////////////////////////////////////////////////////////////////// -// Returns true on success. -bool addDarwinASanLinkFlags(std::vector &args) { - std::string searchPaths[] = { - exe_path::prependLibDir("libldc_rt.asan_osx_dynamic.dylib"), - exe_path::prependLibDir("libclang_rt.asan_osx_dynamic.dylib"), - }; - - for (const auto &filepath : searchPaths) { - if (llvm::sys::fs::exists(filepath)) { - args.push_back(filepath); - - // Add @executable_path to rpath to support having the dylib copied with - // the executable. - args.push_back("-rpath"); - args.push_back("@executable_path"); - - // Add the path to the resource dir to rpath to support using the dylib - // from the default location without copying. - args.push_back("-rpath"); - args.push_back(llvm::sys::path::parent_path(filepath)); - - return true; - } - } - - // We did not find the library. - return false; -} - // Returns the arch name as used in the compiler_rt libs. // FIXME: implement correctly for non-x86 platforms (e.g. ARM) llvm::StringRef getCompilerRTArchName() { return global.params.targetTriple->getArchName(); } -bool addUnixlikeASanLinkFlags(std::vector &args) { +// Returns the libname as full path and with arch suffix and extension. +// For example, with name="libldc_rt.fuzzer", the returned string is +// "libldc_rt.fuzzer_osx.a" on Darwin. +std::string getFullCompilerRTLibPath(llvm::StringRef name, + bool sharedLibrary = false) { + if (global.params.targetTriple->isOSDarwin()) { + return exe_path::prependLibDir( + name + (sharedLibrary ? "_osx_dynamic.dylib" : "_osx.a")); + } else { + return exe_path::prependLibDir(name + "-" + getCompilerRTArchName() + + (sharedLibrary ? ".so" : ".a")); + } +} + +void ArgsBuilder::addASanLinkFlags() { // Examples: "libclang_rt.asan-x86_64.a" or "libclang_rt.asan-arm.a" and // "libclang_rt.asan-x86_64.so" - auto arch = getCompilerRTArchName(); - - // TODO: let user choose to link with shared lib. In case of shared ASan, I - // think we also need to statically link with - // libclang_rt.asan-preinit-.a - bool linkSharedASan = false; - const char *extension = linkSharedASan ? ".so" : ".a"; - + // TODO: let user choose to link with shared lib. + // In case of shared ASan, I think we also need to statically link with + // libclang_rt.asan-preinit-.a on Linux. On Darwin, the only option is + // to use the shared library. + bool linkSharedASan = global.params.targetTriple->isOSDarwin(); std::string searchPaths[] = { - exe_path::prependLibDir("libldc_rt.asan-" + llvm::Twine(arch) + - extension), - exe_path::prependLibDir("libclang_rt.asan-" + llvm::Twine(arch) + - extension), + getFullCompilerRTLibPath("libldc_rt.asan", linkSharedASan), + getFullCompilerRTLibPath("libclang_rt.asan", linkSharedASan), }; for (const auto &filepath : searchPaths) { @@ -239,39 +219,39 @@ bool addUnixlikeASanLinkFlags(std::vector &args) { args.push_back(filepath); if (linkSharedASan) { - // TODO: add -rpath + // Add @executable_path to rpath to support having the shared lib copied + // with the executable. + args.push_back("-rpath"); + args.push_back("@executable_path"); + + // Add the path to the resource dir to rpath to support using the shared + // lib from the default location without copying. + args.push_back("-rpath"); + args.push_back(llvm::sys::path::parent_path(filepath)); } - return true; + return; } } - // We did not find the library. - return false; -} - -void ArgsBuilder::addASanLinkFlags() { - bool success = false; - if (global.params.targetTriple->isOSDarwin()) { - success = addDarwinASanLinkFlags(args); - } else { - success = addUnixlikeASanLinkFlags(args); - } - - if (!success) { - // Fallback, requires Clang. The asan library contains a versioned symbol - // name and a linker error will happen when the LDC-LLVM and Clang-LLVM - // versions don't match. - args.push_back("-fsanitize=address"); - } + // When we reach here, we did not find the ASan library. + // Fallback, requires Clang. The asan library contains a versioned symbol + // name and a linker error will happen when the LDC-LLVM and Clang-LLVM + // versions don't match. + args.push_back("-fsanitize=address"); } // Adds all required link flags for -fsanitize=fuzzer when libFuzzer library is // found. void ArgsBuilder::addFuzzLinkFlags() { std::string searchPaths[] = { +#if LDC_LLVM_VER >= 600 + getFullCompilerRTLibPath("libldc_rt.fuzzer"), + getFullCompilerRTLibPath("libclang_rt.fuzzer"), +#else exe_path::prependLibDir("libFuzzer.a"), exe_path::prependLibDir("libLLVMFuzzer.a"), +#endif }; for (const auto &filepath : searchPaths) { diff --git a/tests/sanitizers/fsanitize_fuzzer.d b/tests/sanitizers/fsanitize_fuzzer.d index caefa7304cd..01293b29d79 100644 --- a/tests/sanitizers/fsanitize_fuzzer.d +++ b/tests/sanitizers/fsanitize_fuzzer.d @@ -10,7 +10,7 @@ bool FuzzMe(const ubyte* data, size_t dataSize) { // CHECK: call {{.*}}_sanitizer_cov_trace_pc_guard - // CHECK: call {{.*}}_sanitizer_cov_trace_cmp + // CHECK: call {{.*}}_sanitizer_cov_trace_{{(const_)?}}cmp return dataSize >= 3 && data[0] == 'F' && diff --git a/tests/sanitizers/link_fuzzer.d b/tests/sanitizers/link_fuzzer.d index 993dab85ff8..57983eef5ea 100644 --- a/tests/sanitizers/link_fuzzer.d +++ b/tests/sanitizers/link_fuzzer.d @@ -5,7 +5,8 @@ // RUN: %ldc -v -fsanitize=fuzzer %s | FileCheck %s // RUN: not %ldc -v -fsanitize=fuzzer -link-no-cpp %s | FileCheck %s --check-prefix=NOCPP -// CHECK: libFuzzer.a +// "libFuzzer.a" before LLVM 6.0, "lib(ldc|clang)_rt.fuzzer.*.a" since LLVM 6.0 +// CHECK: {{(libFuzzer\.a|_rt\.fuzzer.*\.a)}} // CHECK-SAME: -l{{(c|stdc)}}++ // NOCPP-NOT: -l{{(c|stdc)}}++ diff --git a/tests/sanitizers/lit.local.cfg b/tests/sanitizers/lit.local.cfg index 7a7a6edec6e..12cd30154ee 100644 --- a/tests/sanitizers/lit.local.cfg +++ b/tests/sanitizers/lit.local.cfg @@ -9,7 +9,7 @@ if (platform.system() == 'Darwin') or (platform.system() == 'Linux'): if m is not None: config.available_features.add('ASan') continue - m = re.match('.*Fuzzer.*', file) + m = re.match('.*(F|f)uzzer.*', file) if m is not None: config.available_features.add('Fuzzer') continue