Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e126931

Browse files
committedJul 24, 2020
Copy LLVM's ThreadSanitizer (TSan) library to LDC's libraries like we do for ASan, and set the correct linker flags.
TSan is not supported on Windows.
1 parent 4240644 commit e126931

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed
 

‎CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,7 @@ if (LDC_INSTALL_LLVM_RUNTIME_LIBS)
763763

764764
if(APPLE)
765765
copy_compilerrt_lib("darwin/libclang_rt.asan_osx_dynamic.dylib" "libldc_rt.asan.dylib" TRUE)
766+
copy_compilerrt_lib("darwin/libclang_rt.tsan_osx_dynamic.dylib" "libldc_rt.tsan.dylib" TRUE)
766767
copy_compilerrt_lib("darwin/libclang_rt.osx.a" "libldc_rt.builtins.a" FALSE)
767768
copy_compilerrt_lib("darwin/libclang_rt.profile_osx.a" "libldc_rt.profile.a" FALSE)
768769
copy_compilerrt_lib("darwin/libclang_rt.fuzzer_osx.a" "libldc_rt.fuzzer.a" FALSE)
@@ -777,6 +778,7 @@ if (LDC_INSTALL_LLVM_RUNTIME_LIBS)
777778
set(LDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH "x86_64" CACHE STRING "Non-Mac Posix: architecture used as libname suffix for the compiler-rt source libraries, e.g., 'aarch64'.")
778779

779780
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.asan-${LDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH}.a" "libldc_rt.asan.a" FALSE)
781+
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.tsan-${LDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH}.a" "libldc_rt.tsan.a" FALSE)
780782
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.builtins-${LDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH}.a" "libldc_rt.builtins.a" FALSE)
781783
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.profile-${LDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH}.a" "libldc_rt.profile.a" FALSE)
782784
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.xray-${LDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH}.a" "libldc_rt.xray.a" FALSE)

‎driver/linker-gcc.cpp

+43-3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class ArgsBuilder {
5757
private:
5858
virtual void addSanitizers(const llvm::Triple &triple);
5959
virtual void addASanLinkFlags(const llvm::Triple &triple);
60+
virtual void addTSanLinkFlags(const llvm::Triple &triple);
6061
virtual void addFuzzLinkFlags(const llvm::Triple &triple);
6162
virtual void addCppStdlibLinkFlags(const llvm::Triple &triple);
6263
virtual void addProfileRuntimeLinkFlags(const llvm::Triple &triple);
@@ -322,6 +323,47 @@ void ArgsBuilder::addASanLinkFlags(const llvm::Triple &triple) {
322323
args.push_back("-fsanitize=address");
323324
}
324325

326+
void ArgsBuilder::addTSanLinkFlags(const llvm::Triple &triple) {
327+
// Examples: "libclang_rt.tsan-x86_64.a" or "libclang_rt.tsan-arm.a" and
328+
// "libclang_rt.tsan-x86_64.so"
329+
330+
// TODO: let user choose to link with shared lib.
331+
// In case of shared TSan, I think we also need to statically link with
332+
// libclang_rt.tsan-preinit-<arch>.a on Linux. On Darwin, the only option is
333+
// to use the shared library.
334+
bool linkSharedTSan = triple.isOSDarwin();
335+
const auto searchPaths =
336+
getFullCompilerRTLibPathCandidates("tsan", triple, linkSharedTSan);
337+
338+
for (const auto &filepath : searchPaths) {
339+
IF_LOG Logger::println("Searching TSan lib: %s", filepath.c_str());
340+
341+
if (llvm::sys::fs::exists(filepath) &&
342+
!llvm::sys::fs::is_directory(filepath)) {
343+
IF_LOG Logger::println("Found, linking with %s", filepath.c_str());
344+
args.push_back(filepath);
345+
346+
if (linkSharedTSan) {
347+
// Add @executable_path to rpath to support having the shared lib copied
348+
// with the executable.
349+
args.push_back("-rpath");
350+
args.push_back("@executable_path");
351+
352+
// Add the path to the resource dir to rpath to support using the shared
353+
// lib from the default location without copying.
354+
args.push_back("-rpath");
355+
args.push_back(std::string(llvm::sys::path::parent_path(filepath)));
356+
}
357+
358+
return;
359+
}
360+
}
361+
362+
// When we reach here, we did not find the TSan library.
363+
// Fallback, requires Clang.
364+
args.push_back("-fsanitize=thread");
365+
}
366+
325367
// Adds all required link flags for -fsanitize=fuzzer when libFuzzer library is
326368
// found.
327369
void ArgsBuilder::addFuzzLinkFlags(const llvm::Triple &triple) {
@@ -459,10 +501,8 @@ void ArgsBuilder::addSanitizers(const llvm::Triple &triple) {
459501
args.push_back("-fsanitize=memory");
460502
}
461503

462-
// TODO: instead of this, we should link with our own sanitizer libraries
463-
// because LDC's LLVM version could be different from the system clang.
464504
if (opts::isSanitizerEnabled(opts::ThreadSanitizer)) {
465-
args.push_back("-fsanitize=thread");
505+
addTSanLinkFlags(triple);
466506
}
467507
}
468508

‎tests/sanitizers/fsanitize_thread.d

+9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
// Test basic ThreadSanitizer functionality
22

3+
// REQUIRES: TSan
4+
35
// RUN: %ldc -c -output-ll -g -fsanitize=thread -of=%t.ll %s && FileCheck %s < %t.ll
46

7+
// RUN: %ldc -fsanitize=thread %s -of=%t%exe
8+
// RUN: %t%exe
9+
510
// CHECK-LABEL: define {{.*}}D16fsanitize_thread3foo
611
int foo(int i) {
712
// CHECK: call {{.*}}_tsan_func_entry
813
return i + 1;
914
// CHECK: ret i
1015
}
16+
17+
void main() {
18+
foo(0);
19+
}

‎tests/sanitizers/lit.local.cfg

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ if (platform.system() == 'Darwin') or (platform.system() == 'Linux'):
1111
if m is not None:
1212
config.available_features.add('ASan')
1313
continue
14+
m = re.match('.*tsan.*', file)
15+
if m is not None:
16+
config.available_features.add('TSan')
17+
continue
1418
m = re.match('.*(F|f)uzzer.*', file)
1519
if m is not None:
1620
config.available_features.add('Fuzzer')

0 commit comments

Comments
 (0)
Please sign in to comment.