mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 00:55:49 +03:00
Add the -fsanitize-blacklist option for the sanitizers. (#2261)
Blacklisting is necessary for some druntime functions, and LLVM/Clang already provides just the right functionality.
This commit is contained in:
parent
36088a1b49
commit
ec9ffe29f1
6 changed files with 104 additions and 1 deletions
|
@ -15,8 +15,10 @@
|
||||||
#include "driver/cl_options_sanitizers.h"
|
#include "driver/cl_options_sanitizers.h"
|
||||||
|
|
||||||
#include "ddmd/errors.h"
|
#include "ddmd/errors.h"
|
||||||
|
#include "ddmd/dsymbol.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include "llvm/Support/SpecialCaseList.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -28,6 +30,13 @@ cl::list<std::string> fSanitize(
|
||||||
"suspicious behavior."),
|
"suspicious behavior."),
|
||||||
cl::value_desc("checks"));
|
cl::value_desc("checks"));
|
||||||
|
|
||||||
|
cl::list<std::string> fSanitizeBlacklist(
|
||||||
|
"fsanitize-blacklist", cl::CommaSeparated,
|
||||||
|
cl::desc("Add <file> to the blacklist files for the sanitizers."),
|
||||||
|
cl::value_desc("file"));
|
||||||
|
|
||||||
|
std::unique_ptr<llvm::SpecialCaseList> sanitizerBlacklist;
|
||||||
|
|
||||||
#ifdef ENABLE_COVERAGE_SANITIZER
|
#ifdef ENABLE_COVERAGE_SANITIZER
|
||||||
cl::list<std::string> fSanitizeCoverage(
|
cl::list<std::string> fSanitizeCoverage(
|
||||||
"fsanitize-coverage", cl::CommaSeparated,
|
"fsanitize-coverage", cl::CommaSeparated,
|
||||||
|
@ -149,6 +158,14 @@ void initializeSanitizerOptionsFromCmdline()
|
||||||
sancovOpts.CoverageType = llvm::SanitizerCoverageOptions::SCK_Edge;
|
sancovOpts.CoverageType = llvm::SanitizerCoverageOptions::SCK_Edge;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (isAnySanitizerEnabled() && !fSanitizeBlacklist.empty()) {
|
||||||
|
std::string loadError;
|
||||||
|
sanitizerBlacklist =
|
||||||
|
llvm::SpecialCaseList::create(fSanitizeBlacklist, loadError);
|
||||||
|
if (!sanitizerBlacklist)
|
||||||
|
error(Loc(), "-fsanitize-blacklist error: %s", loadError.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_COVERAGE_SANITIZER
|
#ifdef ENABLE_COVERAGE_SANITIZER
|
||||||
|
@ -180,4 +197,9 @@ void outputSanitizerSettings(llvm::raw_ostream &hash_os) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool functionIsInSanitizerBlacklist(FuncDeclaration *funcDecl) {
|
||||||
|
return sanitizerBlacklist &&
|
||||||
|
sanitizerBlacklist->inSection("fun", mangleExact(funcDecl));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace opts
|
} // namespace opts
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define ENABLE_COVERAGE_SANITIZER
|
#define ENABLE_COVERAGE_SANITIZER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class FuncDeclaration;
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class raw_ostream;
|
class raw_ostream;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +55,8 @@ llvm::SanitizerCoverageOptions getSanitizerCoverageOptions();
|
||||||
|
|
||||||
void outputSanitizerSettings(llvm::raw_ostream &hash_os);
|
void outputSanitizerSettings(llvm::raw_ostream &hash_os);
|
||||||
|
|
||||||
|
bool functionIsInSanitizerBlacklist(FuncDeclaration *funcDecl);
|
||||||
|
|
||||||
} // namespace opts
|
} // namespace opts
|
||||||
|
|
||||||
#endif // LDC_DRIVER_CL_OPTIONS_SANITIZERS_H
|
#endif // LDC_DRIVER_CL_OPTIONS_SANITIZERS_H
|
||||||
|
|
|
@ -954,7 +954,8 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
if (gABI->needsUnwindTables()) {
|
if (gABI->needsUnwindTables()) {
|
||||||
func->addFnAttr(LLAttribute::UWTable);
|
func->addFnAttr(LLAttribute::UWTable);
|
||||||
}
|
}
|
||||||
if (opts::isAnySanitizerEnabled()) {
|
if (opts::isAnySanitizerEnabled() &&
|
||||||
|
!opts::functionIsInSanitizerBlacklist(fd)) {
|
||||||
// Set the required sanitizer attribute.
|
// Set the required sanitizer attribute.
|
||||||
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
|
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
|
||||||
func->addFnAttr(LLAttribute::SanitizeAddress);
|
func->addFnAttr(LLAttribute::SanitizeAddress);
|
||||||
|
|
63
tests/sanitizers/fsanitize_blacklist.d
Normal file
63
tests/sanitizers/fsanitize_blacklist.d
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
// Test sanitizer blacklist functionality
|
||||||
|
|
||||||
|
// RUN: %ldc -c -output-ll -fsanitize=address \
|
||||||
|
// RUN: -fsanitize-blacklist=%S/inputs/fsanitize_blacklist.txt \
|
||||||
|
// RUN: -fsanitize-blacklist=%S/inputs/fsanitize_blacklist2.txt \
|
||||||
|
// RUN: -of=%t.ll %s && FileCheck %s < %t.ll
|
||||||
|
|
||||||
|
// Don't attempt to load the blacklist when no sanitizer is active
|
||||||
|
// RUN: %ldc -o- -fsanitize-blacklist=%S/thisfilecertainlydoesnotexist %s
|
||||||
|
|
||||||
|
// CHECK-LABEL: define {{.*}}9foofoofoo
|
||||||
|
// CHECK-SAME: #[[ATTR_WITHASAN:[0-9]+]]
|
||||||
|
void foofoofoo(int* i)
|
||||||
|
{
|
||||||
|
// CHECK: call {{.*}}_asan
|
||||||
|
*i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define {{.*}}blacklisted
|
||||||
|
// CHECK-SAME: #[[ATTR_NOASAN:[0-9]+]]
|
||||||
|
extern (C) void blacklisted(int* i)
|
||||||
|
{
|
||||||
|
// CHECK-NOT: call {{.*}}_asan
|
||||||
|
*i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test blacklisted wildcard
|
||||||
|
// CHECK-LABEL: define {{.*}}10black_set1
|
||||||
|
// CHECK-SAME: #[[ATTR_NOASAN:[0-9]+]]
|
||||||
|
void black_set1(int* i)
|
||||||
|
{
|
||||||
|
// CHECK-NOT: call {{.*}}_asan
|
||||||
|
*i = 1;
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: define {{.*}}10black_set2
|
||||||
|
// CHECK-SAME: #[[ATTR_NOASAN:[0-9]+]]
|
||||||
|
void black_set2(int* i)
|
||||||
|
{
|
||||||
|
// CHECK-NOT: call {{.*}}_asan
|
||||||
|
*i = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test blacklisting of template class methods
|
||||||
|
class ABCDEF(T)
|
||||||
|
{
|
||||||
|
void method(int* i)
|
||||||
|
{
|
||||||
|
*i = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define {{.*}}TiZ6ABCDEF6method
|
||||||
|
// CHECK-SAME: #[[ATTR_NOASAN:[0-9]+]]
|
||||||
|
ABCDEF!int ofBlacklistedType;
|
||||||
|
|
||||||
|
// CHECK-LABEL: define {{.*}}TAyaZ6ABCDEF6method
|
||||||
|
// CHECK-SAME: #[[ATTR_WITHASAN:[0-9]+]]
|
||||||
|
ABCDEF!string ofInstrumentedType;
|
||||||
|
|
||||||
|
//CHECK: attributes #[[ATTR_WITHASAN]] ={{.*}}sanitize_address
|
||||||
|
//CHECK: attributes #[[ATTR_NOASAN]]
|
||||||
|
//CHECK-NOT: sanitize_address
|
||||||
|
//CHECK-SAME: }
|
13
tests/sanitizers/inputs/fsanitize_blacklist.txt
Normal file
13
tests/sanitizers/inputs/fsanitize_blacklist.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Blacklist for the sanitizers. Turns off instrumentation of particular
|
||||||
|
# functions or sources. Use with care. You may set location of blacklist
|
||||||
|
# at compile-time using -fsanitize-blacklist=<path> flag.
|
||||||
|
|
||||||
|
# Example usage:
|
||||||
|
# fun:*bad_function_name*
|
||||||
|
# src:file_with_tricky_code.cc
|
||||||
|
# global:*global_with_bad_access_or_initialization*
|
||||||
|
# global:*global_with_initialization_issues*=init
|
||||||
|
# type:*Namespace::ClassName*=init
|
||||||
|
|
||||||
|
fun:blacklisted
|
||||||
|
fun:*black_set*
|
1
tests/sanitizers/inputs/fsanitize_blacklist2.txt
Normal file
1
tests/sanitizers/inputs/fsanitize_blacklist2.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
fun:_D*TiZ6ABCDEF6method*
|
Loading…
Add table
Add a link
Reference in a new issue