SanitizerBlacklist: blacklist functions by their source location.

This commit changes the way we blacklist functions in ASan, TSan,
MSan and UBSan. We used to treat function as "blacklisted"
and turned off instrumentation in it in two cases:

1) Function is explicitly blacklisted by its mangled name.
This part is not changed.

2) Function is located in llvm::Module, whose identifier is
contained in the list of blacklisted sources. This is completely
wrong, as llvm::Module may not correspond to the actual source
file function is defined in. Also, function can be defined in
a header, in which case user had to blacklist the .cpp file
this header was #include'd into, not the header itself.
Such functions could cause other problems - for instance, if the
header was included in multiple source files, compiled
separately and linked into a single executable, we could end up
with both instrumented and non-instrumented version of the same
function participating in the same link.

After this change we will make blacklisting decision based on
the SourceLocation of a function definition. If a function is
not explicitly defined in the source file, (for example, the
function is compiler-generated and responsible for
initialization/destruction of a global variable), then it will
be blacklisted if the corresponding global variable is defined
in blacklisted source file, and will be instrumented otherwise.

After this commit, the active users of blacklist files may have
to revisit them. This is a backwards-incompatible change, but
I don't think it's possible or makes sense to support the
old incorrect behavior.

I plan to make similar change for blacklisting GlobalVariables
(which is ASan-specific).

llvm-svn: 219997
This commit is contained in:
Alexey Samsonov 2014-10-17 00:20:19 +00:00
parent 3514242a66
commit 1444bb9fc8
11 changed files with 83 additions and 44 deletions

View File

@ -23,7 +23,6 @@
namespace llvm { namespace llvm {
class GlobalVariable; class GlobalVariable;
class Function;
} }
namespace clang { namespace clang {
@ -34,7 +33,6 @@ class SanitizerBlacklist {
public: public:
SanitizerBlacklist(StringRef BlacklistPath, SourceManager &SM); SanitizerBlacklist(StringRef BlacklistPath, SourceManager &SM);
bool isIn(const llvm::Function &F) const;
bool isIn(const llvm::GlobalVariable &G, bool isIn(const llvm::GlobalVariable &G,
StringRef Category = StringRef()) const; StringRef Category = StringRef()) const;
bool isBlacklistedType(StringRef MangledTypeName, bool isBlacklistedType(StringRef MangledTypeName,

View File

@ -12,7 +12,6 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "clang/Basic/SanitizerBlacklist.h" #include "clang/Basic/SanitizerBlacklist.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
@ -33,11 +32,6 @@ SanitizerBlacklist::SanitizerBlacklist(StringRef BlacklistPath,
SourceManager &SM) SourceManager &SM)
: SCL(llvm::SpecialCaseList::createOrDie(BlacklistPath)), SM(SM) {} : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPath)), SM(SM) {}
bool SanitizerBlacklist::isIn(const llvm::Function &F) const {
return isBlacklistedFile(F.getParent()->getModuleIdentifier()) ||
isBlacklistedFunction(F.getName());
}
bool SanitizerBlacklist::isIn(const llvm::GlobalVariable &G, bool SanitizerBlacklist::isIn(const llvm::GlobalVariable &G,
StringRef Category) const { StringRef Category) const {
return isBlacklistedFile(G.getParent()->getModuleIdentifier(), Category) || return isBlacklistedFile(G.getParent()->getModuleIdentifier(), Category) ||

View File

@ -167,7 +167,8 @@ llvm::Constant *CodeGenFunction::createAtExitStub(const VarDecl &VD,
llvm::raw_svector_ostream Out(FnName); llvm::raw_svector_ostream Out(FnName);
CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&VD, Out); CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&VD, Out);
} }
llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(ty, FnName.str()); llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(ty, FnName.str(),
VD.getLocation());
CodeGenFunction CGF(CGM); CodeGenFunction CGF(CGM);
@ -219,9 +220,8 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit); CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
} }
llvm::Function * llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
CodeGenModule::CreateGlobalInitOrDestructFunction(llvm::FunctionType *FTy, llvm::FunctionType *FTy, const Twine &Name, SourceLocation Loc, bool TLS) {
const Twine &Name, bool TLS) {
llvm::Function *Fn = llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
Name, &getModule()); Name, &getModule());
@ -236,7 +236,7 @@ CodeGenModule::CreateGlobalInitOrDestructFunction(llvm::FunctionType *FTy,
if (!getLangOpts().Exceptions) if (!getLangOpts().Exceptions)
Fn->setDoesNotThrow(); Fn->setDoesNotThrow();
if (!getSanitizerBlacklist().isIn(*Fn)) { if (!isInSanitizerBlacklist(Fn, Loc)) {
if (getLangOpts().Sanitize.Address) if (getLangOpts().Sanitize.Address)
Fn->addFnAttr(llvm::Attribute::SanitizeAddress); Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
if (getLangOpts().Sanitize.Thread) if (getLangOpts().Sanitize.Thread)
@ -286,7 +286,8 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
} }
// Create a variable initialization function. // Create a variable initialization function.
llvm::Function *Fn = CreateGlobalInitOrDestructFunction(FTy, FnName.str()); llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(FTy, FnName.str(), D->getLocation());
auto *ISA = D->getAttr<InitSegAttr>(); auto *ISA = D->getAttr<InitSegAttr>();
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr, CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
@ -552,8 +553,8 @@ llvm::Function *CodeGenFunction::generateDestroyHelper(
const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration( const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
getContext().VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false); getContext().VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI); llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *fn = llvm::Function *fn = CGM.CreateGlobalInitOrDestructFunction(
CGM.CreateGlobalInitOrDestructFunction(FTy, "__cxx_global_array_dtor"); FTy, "__cxx_global_array_dtor", VD->getLocation());
StartFunction(VD, getContext().VoidTy, fn, FI, args); StartFunction(VD, getContext().VoidTy, fn, FI, args);

View File

@ -552,7 +552,8 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
Out); Out);
// Blacklist based on the mangled type. // Blacklist based on the mangled type.
if (!CGM.getSanitizerBlacklist().isBlacklistedType(Out.str())) { if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType(
Out.str())) {
llvm::hash_code TypeHash = hash_value(Out.str()); llvm::hash_code TypeHash = hash_value(Out.str());
// Load the vptr, and compute hash_16_bytes(TypeHash, vptr). // Load the vptr, and compute hash_16_bytes(TypeHash, vptr).

View File

@ -579,7 +579,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
CurFnInfo = &FnInfo; CurFnInfo = &FnInfo;
assert(CurFn->isDeclaration() && "Function already has body?"); assert(CurFn->isDeclaration() && "Function already has body?");
if (CGM.getSanitizerBlacklist().isIn(*Fn)) if (CGM.isInSanitizerBlacklist(Fn, Loc))
SanOpts = &SanitizerOptions::Disabled; SanOpts = &SanitizerOptions::Disabled;
// Pass inline keyword to optimizer if it appears explicitly on any // Pass inline keyword to optimizer if it appears explicitly on any

View File

@ -740,7 +740,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::StackProtectReq); B.addAttribute(llvm::Attribute::StackProtectReq);
// Add sanitizer attributes if function is not blacklisted. // Add sanitizer attributes if function is not blacklisted.
if (!getSanitizerBlacklist().isIn(*F)) { if (!isInSanitizerBlacklist(F, D->getLocation())) {
// When AddressSanitizer is enabled, set SanitizeAddress attribute // When AddressSanitizer is enabled, set SanitizeAddress attribute
// unless __attribute__((no_sanitize_address)) is used. // unless __attribute__((no_sanitize_address)) is used.
if (LangOpts.Sanitize.Address && !D->hasAttr<NoSanitizeAddressAttr>()) if (LangOpts.Sanitize.Address && !D->hasAttr<NoSanitizeAddressAttr>())
@ -1168,6 +1168,24 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation())); Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
} }
bool CodeGenModule::isInSanitizerBlacklist(llvm::Function *Fn,
SourceLocation Loc) const {
const auto &SanitizerBL = getContext().getSanitizerBlacklist();
// Blacklist by function name.
if (SanitizerBL.isBlacklistedFunction(Fn->getName()))
return true;
// Blacklist by location.
if (!Loc.isInvalid())
return SanitizerBL.isBlacklistedLocation(Loc);
// If location is unknown, this may be a compiler-generated function. Assume
// it's located in the main file.
auto &SM = Context.getSourceManager();
if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
return SanitizerBL.isBlacklistedFile(MainFile->getName());
}
return false;
}
bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified. // Never defer when EmitAllDecls is specified.
if (LangOpts.EmitAllDecls) if (LangOpts.EmitAllDecls)

View File

@ -686,9 +686,10 @@ public:
CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty, CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty,
llvm::GlobalValue::LinkageTypes Linkage); llvm::GlobalValue::LinkageTypes Linkage);
llvm::Function *CreateGlobalInitOrDestructFunction(llvm::FunctionType *ty, llvm::Function *
const Twine &name, CreateGlobalInitOrDestructFunction(llvm::FunctionType *ty, const Twine &name,
bool TLS = false); SourceLocation Loc = SourceLocation(),
bool TLS = false);
/// Return the address space of the underlying global variable for D, as /// Return the address space of the underlying global variable for D, as
/// determined by its declaration. Normally this is the same as the address /// determined by its declaration. Normally this is the same as the address
@ -1045,9 +1046,7 @@ public:
/// annotations are emitted during finalization of the LLVM code. /// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV); void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
const SanitizerBlacklist &getSanitizerBlacklist() const { bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const;
return Context.getSanitizerBlacklist();
}
SanitizerMetadata *getSanitizerMetadata() { SanitizerMetadata *getSanitizerMetadata() {
return SanitizerMD.get(); return SanitizerMD.get();

View File

@ -1912,6 +1912,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
llvm::FunctionType *FTy = llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
InitFunc = CGM.CreateGlobalInitOrDestructFunction(FTy, "__tls_init", InitFunc = CGM.CreateGlobalInitOrDestructFunction(FTy, "__tls_init",
SourceLocation(),
/*TLS=*/true); /*TLS=*/true);
llvm::GlobalVariable *Guard = new llvm::GlobalVariable( llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false, CGM.getModule(), CGM.Int8Ty, /*isConstant=*/false,

View File

@ -1796,9 +1796,9 @@ void MicrosoftCXXABI::EmitThreadLocalInitFuncs(
if (!NonComdatInits.empty()) { if (!NonComdatInits.empty()) {
llvm::FunctionType *FTy = llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
llvm::Function *InitFunc = llvm::Function *InitFunc = CGM.CreateGlobalInitOrDestructFunction(
CGM.CreateGlobalInitOrDestructFunction(FTy, "__tls_init", FTy, "__tls_init", SourceLocation(),
/*TLS=*/true); /*TLS=*/true);
CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(InitFunc, NonComdatInits); CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(InitFunc, NonComdatInits);
AddToXDU(InitFunc); AddToXDU(InitFunc);

View File

@ -25,8 +25,8 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
bool IsDynInit, bool IsBlacklisted) { bool IsDynInit, bool IsBlacklisted) {
if (!CGM.getLangOpts().Sanitize.Address) if (!CGM.getLangOpts().Sanitize.Address)
return; return;
IsDynInit &= !CGM.getSanitizerBlacklist().isIn(*GV, "init"); IsDynInit &= !CGM.getContext().getSanitizerBlacklist().isIn(*GV, "init");
IsBlacklisted |= CGM.getSanitizerBlacklist().isIn(*GV); IsBlacklisted |= CGM.getContext().getSanitizerBlacklist().isIn(*GV);
llvm::Value *LocDescr = nullptr; llvm::Value *LocDescr = nullptr;
llvm::Value *GlobalName = nullptr; llvm::Value *GlobalName = nullptr;

View File

@ -1,9 +1,16 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s int DefinedInDifferentFile(int *a);
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix=ASAN %s // RUN: echo "int DefinedInDifferentFile(int *a) { return *a; }" > %t.extra-source.cpp
// RUN: echo "src:%s" > %t.file.blacklist // RUN: echo "struct S { S(){} ~S(){} };" >> %t.extra-source.cpp
// RUN: echo "S glob_array[5];" >> %t.extra-source.cpp
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp | FileCheck -check-prefix=WITHOUT %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address | FileCheck -check-prefix=ASAN %s
// RUN: echo "fun:*BlacklistedFunction*" > %t.func.blacklist // RUN: echo "fun:*BlacklistedFunction*" > %t.func.blacklist
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
// RUN: echo "src:%s" > %t.file.blacklist
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
// FIXME: %t.file.blacklist is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp" // FIXME: %t.file.blacklist is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp"
// REQUIRES: shell // REQUIRES: shell
@ -12,7 +19,25 @@
// when AddressSanitizer is enabled, unless no_sanitize_address attribute // when AddressSanitizer is enabled, unless no_sanitize_address attribute
// is present. // is present.
// WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] // Attributes for function defined in different source file:
// WITHOUT: DefinedInDifferentFile{{.*}} [[NOATTR:#[0-9]+]]
// BLFILE: DefinedInDifferentFile{{.*}} [[WITH:#[0-9]+]]
// BLFUNC: DefinedInDifferentFile{{.*}} [[WITH:#[0-9]+]]
// ASAN: DefinedInDifferentFile{{.*}} [[WITH:#[0-9]+]]
// Check that functions generated for global in different source file are
// not blacklisted.
// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
// WITHOUT: @__cxx_global_array_dtor{{.*}}[[NOATTR_NO_TF]]
// BLFILE: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
// BLFILE: @__cxx_global_array_dtor{{.*}}[[WITH_NO_TF]]
// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
// BLFUNC: @__cxx_global_array_dtor{{.*}}[[WITH_NO_TF]]
// ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
// ASAN: @__cxx_global_array_dtor{{.*}}[[WITH_NO_TF]]
// WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR]]
// BLFILE: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] // BLFILE: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
// BLFUNC: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] // BLFUNC: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
// ASAN: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]] // ASAN: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
@ -29,8 +54,8 @@ int NoAddressSafety2(int *a) { return *a; }
// WITHOUT: AddressSafetyOk{{.*}}) [[NOATTR]] // WITHOUT: AddressSafetyOk{{.*}}) [[NOATTR]]
// BLFILE: AddressSafetyOk{{.*}}) [[NOATTR]] // BLFILE: AddressSafetyOk{{.*}}) [[NOATTR]]
// BLFUNC: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]] // BLFUNC: AddressSafetyOk{{.*}}) [[WITH]]
// ASAN: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]] // ASAN: AddressSafetyOk{{.*}}) [[WITH]]
int AddressSafetyOk(int *a) { return *a; } int AddressSafetyOk(int *a) { return *a; }
// WITHOUT: BlacklistedFunction{{.*}}) [[NOATTR]] // WITHOUT: BlacklistedFunction{{.*}}) [[NOATTR]]
@ -60,21 +85,23 @@ int force_instance = TemplateAddressSafetyOk<42>()
// Check that __cxx_global_var_init* get the sanitize_address attribute. // Check that __cxx_global_var_init* get the sanitize_address attribute.
int global1 = 0; int global1 = 0;
int global2 = *(int*)((char*)&global1+1); int global2 = *(int*)((char*)&global1+1);
// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]] // WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF]]
// BLFILE: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]] // BLFILE: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]] // BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF]]
// ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]] // ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF]]
// WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} } // WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} }
// WITHOUT: attributes [[NOATTR_NO_TF]] = { nounwind } // WITHOUT: attributes [[NOATTR_NO_TF]] = { nounwind }
// BLFILE: attributes [[NOATTR]] = { nounwind{{.*}} } // BLFILE: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
// BLFILE: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
// BLFILE: attributes [[NOATTR_NO_TF]] = { nounwind } // BLFILE: attributes [[NOATTR_NO_TF]] = { nounwind }
// BLFILE: attributes [[NOATTR]] = { nounwind{{.*}} }
// BLFUNC: attributes [[NOATTR]] = { nounwind{{.*}} }
// BLFUNC: attributes [[WITH]] = { nounwind sanitize_address{{.*}} } // BLFUNC: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
// BLFUNC: attributes [[WITH_NO_TF]] = { nounwind sanitize_address } // BLFUNC: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
// BLFUNC: attributes [[NOATTR]] = { nounwind{{.*}} }
// ASAN: attributes [[NOATTR]] = { nounwind{{.*}} }
// ASAN: attributes [[WITH]] = { nounwind sanitize_address{{.*}} } // ASAN: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
// ASAN: attributes [[WITH_NO_TF]] = { nounwind sanitize_address } // ASAN: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
// ASAN: attributes [[NOATTR]] = { nounwind{{.*}} }