Skip to content

Commit

Permalink
Add LeakSanitizer support with -fsanitize=leak (#4005)
Browse files Browse the repository at this point in the history
* Add LeakSanitizer support

* Windows and FreeBSD do not support LSan yet

* Test LLVM >= 10 only with LSan
  • Loading branch information
JohanEngelen committed Jun 26, 2022
1 parent a2ce3f3 commit 3b9665b
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,7 @@ if (LDC_INSTALL_LLVM_RUNTIME_LIBS)

if(APPLE)
copy_compilerrt_lib("darwin/libclang_rt.asan_osx_dynamic.dylib" "libldc_rt.asan.dylib" TRUE)
copy_compilerrt_lib("darwin/libclang_rt.lsan_osx_dynamic.dylib" "libldc_rt.lsan.dylib" TRUE)
copy_compilerrt_lib("darwin/libclang_rt.tsan_osx_dynamic.dylib" "libldc_rt.tsan.dylib" TRUE)
copy_compilerrt_lib("darwin/libclang_rt.osx.a" "libldc_rt.builtins.a" FALSE)
copy_compilerrt_lib("darwin/libclang_rt.profile_osx.a" "libldc_rt.profile.a" FALSE)
Expand All @@ -805,6 +806,7 @@ if (LDC_INSTALL_LLVM_RUNTIME_LIBS)
endif()

copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.asan${compilerrt_suffix}.a" "libldc_rt.asan.a" FALSE)
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.lsan${compilerrt_suffix}.a" "libldc_rt.lsan.a" FALSE)
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.msan${compilerrt_suffix}.a" "libldc_rt.msan.a" FALSE)
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.tsan${compilerrt_suffix}.a" "libldc_rt.tsan.a" FALSE)
copy_compilerrt_lib("${LDC_INSTALL_LLVM_RUNTIME_LIBS_OS}/libclang_rt.builtins${compilerrt_suffix}.a" "libldc_rt.builtins.a" FALSE)
Expand All @@ -820,6 +822,7 @@ if (LDC_INSTALL_LLVM_RUNTIME_LIBS)
set(compilerrt_arch_suffix "i386")
endif()
copy_compilerrt_lib("windows/clang_rt.asan-${compilerrt_arch_suffix}.lib" "ldc_rt.asan.lib" FALSE)
copy_compilerrt_lib("windows/clang_rt.lsan-${compilerrt_arch_suffix}.lib" "ldc_rt.lsan.lib" FALSE)
copy_compilerrt_lib("windows/clang_rt.builtins-${compilerrt_arch_suffix}.lib" "ldc_rt.builtins.lib" FALSE)
copy_compilerrt_lib("windows/clang_rt.profile-${compilerrt_arch_suffix}.lib" "ldc_rt.profile.lib" FALSE)
copy_compilerrt_lib("windows/clang_rt.fuzzer-${compilerrt_arch_suffix}.lib" "ldc_rt.fuzzer.lib" FALSE)
Expand Down
1 change: 1 addition & 0 deletions driver/cl_options_sanitizers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ SanitizerCheck parseSanitizerName(llvm::StringRef name,
SanitizerCheck parsedValue = llvm::StringSwitch<SanitizerCheck>(name)
.Case("address", AddressSanitizer)
.Case("fuzzer", FuzzSanitizer)
.Case("leak", LeakSanitizer)
.Case("memory", MemorySanitizer)
.Case("thread", ThreadSanitizer)
.Default(NoneSanitizer);
Expand Down
3 changes: 2 additions & 1 deletion driver/cl_options_sanitizers.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ enum SanitizerCheck : SanitizerBits {
FuzzSanitizer = 1 << 1,
MemorySanitizer = 1 << 2,
ThreadSanitizer = 1 << 3,
CoverageSanitizer = 1 << 4
CoverageSanitizer = 1 << 4,
LeakSanitizer = 1 << 5,
};
extern SanitizerBits enabledSanitizers;

Expand Down
3 changes: 3 additions & 0 deletions driver/linker-gcc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,9 @@ void ArgsBuilder::addProfileRuntimeLinkFlags(const llvm::Triple &triple) {
void ArgsBuilder::addSanitizers(const llvm::Triple &triple) {
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
addSanitizerLinkFlags(triple, "asan", "-fsanitize=address");
} else if (opts::isSanitizerEnabled(opts::LeakSanitizer)) {
// If ASan is enabled, it includes LSan. So only add LSan link flags if ASan is _not_ enabled already.
addSanitizerLinkFlags(triple, "lsan", "-fsanitize=leak");
}

if (opts::isSanitizerEnabled(opts::FuzzSanitizer)) {
Expand Down
3 changes: 3 additions & 0 deletions driver/linker-msvc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ void addLibIfFound(std::vector<std::string> &args, const llvm::Twine &name) {
void addSanitizerLibs(std::vector<std::string> &args) {
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
args.push_back("ldc_rt.asan.lib");
} else if (opts::isSanitizerEnabled(opts::LeakSanitizer)) {
// If ASan is enabled, it includes LSan. So only add LSan link flags if ASan is _not_ enabled already.
args.push_back("ldc_rt.lsan.lib");
}
if (opts::isSanitizerEnabled(opts::FuzzSanitizer)) {
args.push_back("ldc_rt.fuzzer.lib");
Expand Down
3 changes: 2 additions & 1 deletion tests/sanitizers/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import os
import platform

# Add "ASan" feature, assuming the compiler-rt library is available
# Add "ASan" and "LSan" features, assuming the compiler-rt library is available
config.available_features.add('ASan')
config.available_features.add('LSan')

# FreeBSD TSan needs https://reviews.llvm.org/D85292,
# Linux TSan currently only works with static druntime,
Expand Down
26 changes: 26 additions & 0 deletions tests/sanitizers/lsan_memleak.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Test leak detection with LSan

// REQUIRES: LSan && atleast_llvm1000

// UNSUPPORTED: Windows, FreeBSD

// RUN: %ldc -g -fsanitize=address %s -of=%t_asan%exe
// RUN: not env %env_asan_opts=detect_leaks=true %t_asan%exe 2>&1 | FileCheck %s
// RUN: %ldc -g -fsanitize=leak %s -of=%t%exe
// RUN: not %t%exe 2>&1 | FileCheck %s

import core.stdc.stdlib;

// CHECK: ERROR: LeakSanitizer: detected memory leaks

void* foo()
{
// CHECK: Direct leak of 17 byte(s) in 1 object(s) allocated from:
// CHECK: #{{.*}} in {{.*}}lsan_memleak.d:[[@LINE+1]]
return malloc(17);
}

void main()
{
foo();
}

0 comments on commit 3b9665b

Please sign in to comment.