Index: include/clang/Basic/SanitizerBlacklist.h =================================================================== --- include/clang/Basic/SanitizerBlacklist.h +++ include/clang/Basic/SanitizerBlacklist.h @@ -15,29 +15,30 @@ #define LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H #include "clang/Basic/LLVM.h" +#include "clang/Basic/SanitizerSpecialCaseList.h" +#include "clang/Basic/Sanitizers.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/SpecialCaseList.h" #include namespace clang { class SanitizerBlacklist { - std::unique_ptr SCL; + std::unique_ptr SSCL; SourceManager &SM; public: SanitizerBlacklist(const std::vector &BlacklistPaths, SourceManager &SM); - bool isBlacklistedGlobal(StringRef GlobalName, + bool isBlacklistedGlobal(SanitizerMask Mask, StringRef GlobalName, StringRef Category = StringRef()) const; - bool isBlacklistedType(StringRef MangledTypeName, + bool isBlacklistedType(SanitizerMask Mask, StringRef MangledTypeName, StringRef Category = StringRef()) const; - bool isBlacklistedFunction(StringRef FunctionName) const; - bool isBlacklistedFile(StringRef FileName, + bool isBlacklistedFunction(SanitizerMask Mask, StringRef FunctionName) const; + bool isBlacklistedFile(SanitizerMask Mask, StringRef FileName, StringRef Category = StringRef()) const; - bool isBlacklistedLocation(SourceLocation Loc, + bool isBlacklistedLocation(SanitizerMask Mask, SourceLocation Loc, StringRef Category = StringRef()) const; }; Index: include/clang/Basic/SanitizerSpecialCaseList.h =================================================================== --- /dev/null +++ include/clang/Basic/SanitizerSpecialCaseList.h @@ -0,0 +1,53 @@ +//===--- SanitizerSpecialCaseList.h - SCL for sanitizers --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// An extension of SpecialCaseList to allowing querying sections by +// SanitizerMask. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H +#define LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Sanitizers.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/SpecialCaseList.h" +#include + +namespace clang { + +class SanitizerSpecialCaseList : public llvm::SpecialCaseList { +public: + static std::unique_ptr + create(const std::vector &Paths, std::string &Error); + + static std::unique_ptr + createOrDie(const std::vector &Paths); + + bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query, + StringRef Category = StringRef()) const; + +protected: + // Override compile to also initialize SanitizerSections. + virtual void compile(llvm::StringMap &SectionsMap); + + struct SanitizerSection { + SanitizerSection(SanitizerMask SM, SectionEntries &E) + : Mask(SM), Entries(E){}; + + SanitizerMask Mask; + SectionEntries &Entries; + }; + + std::vector SanitizerSections; +}; + +} // end namespace clang + +#endif Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -3929,8 +3929,9 @@ bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const { ASTContext &Context = getASTContext(); - if (!Context.getLangOpts().Sanitize.hasOneOf( - SanitizerKind::Address | SanitizerKind::KernelAddress) || + const SanitizerMask ASanMask = + SanitizerKind::Address | SanitizerKind::KernelAddress; + if (!Context.getLangOpts().Sanitize.hasOneOf(ASanMask) || !Context.getLangOpts().SanitizeAddressFieldPadding) return false; const auto &Blacklist = Context.getSanitizerBlacklist(); @@ -3949,9 +3950,10 @@ ReasonToReject = 4; // has trivial destructor. else if (CXXRD->isStandardLayout()) ReasonToReject = 5; // is standard layout. - else if (Blacklist.isBlacklistedLocation(getLocation(), "field-padding")) + else if (Blacklist.isBlacklistedLocation(ASanMask, getLocation(), + "field-padding")) ReasonToReject = 6; // is in a blacklisted file. - else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(), + else if (Blacklist.isBlacklistedType(ASanMask, getQualifiedNameAsString(), "field-padding")) ReasonToReject = 7; // is blacklisted. Index: lib/Basic/CMakeLists.txt =================================================================== --- lib/Basic/CMakeLists.txt +++ lib/Basic/CMakeLists.txt @@ -62,6 +62,7 @@ OpenMPKinds.cpp OperatorPrecedence.cpp SanitizerBlacklist.cpp + SanitizerSpecialCaseList.cpp Sanitizers.cpp SourceLocation.cpp SourceManager.cpp Index: lib/Basic/SanitizerBlacklist.cpp =================================================================== --- lib/Basic/SanitizerBlacklist.cpp +++ lib/Basic/SanitizerBlacklist.cpp @@ -17,30 +17,35 @@ SanitizerBlacklist::SanitizerBlacklist( const std::vector &BlacklistPaths, SourceManager &SM) - : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} + : SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} -bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName, +bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask, + StringRef GlobalName, StringRef Category) const { - return SCL->inSection("global", GlobalName, Category); + return SSCL->inSection(Mask, "global", GlobalName, Category); } -bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName, +bool SanitizerBlacklist::isBlacklistedType(SanitizerMask Mask, + StringRef MangledTypeName, StringRef Category) const { - return SCL->inSection("type", MangledTypeName, Category); + return SSCL->inSection(Mask, "type", MangledTypeName, Category); } -bool SanitizerBlacklist::isBlacklistedFunction(StringRef FunctionName) const { - return SCL->inSection("fun", FunctionName); +bool SanitizerBlacklist::isBlacklistedFunction(SanitizerMask Mask, + StringRef FunctionName) const { + return SSCL->inSection(Mask, "fun", FunctionName); } -bool SanitizerBlacklist::isBlacklistedFile(StringRef FileName, +bool SanitizerBlacklist::isBlacklistedFile(SanitizerMask Mask, + StringRef FileName, StringRef Category) const { - return SCL->inSection("src", FileName, Category); + return SSCL->inSection(Mask, "src", FileName, Category); } -bool SanitizerBlacklist::isBlacklistedLocation(SourceLocation Loc, +bool SanitizerBlacklist::isBlacklistedLocation(SanitizerMask Mask, + SourceLocation Loc, StringRef Category) const { return Loc.isValid() && - isBlacklistedFile(SM.getFilename(SM.getFileLoc(Loc)), Category); + isBlacklistedFile(Mask, SM.getFilename(SM.getFileLoc(Loc)), Category); } Index: lib/Basic/SanitizerSpecialCaseList.cpp =================================================================== --- /dev/null +++ lib/Basic/SanitizerSpecialCaseList.cpp @@ -0,0 +1,66 @@ +//===--- SanitizerSpecialCaseList.cpp - SCL for sanitizers ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// An extension of SpecialCaseList to allowing querying sections by +// SanitizerMask. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/SanitizerSpecialCaseList.h" + +using namespace clang; + +std::unique_ptr +SanitizerSpecialCaseList::create(const std::vector &Paths, + std::string &Error) { + std::unique_ptr SSCL( + new SanitizerSpecialCaseList()); + if (SSCL->createInternal(Paths, Error)) + return SSCL; + return nullptr; +} + +std::unique_ptr +SanitizerSpecialCaseList::createOrDie(const std::vector &Paths) { + std::string Error; + if (auto SSCL = create(Paths, Error)) + return SSCL; + llvm::report_fatal_error(Error); +} + +void SanitizerSpecialCaseList::compile( + llvm::StringMap &SectionsMap) { + SpecialCaseList::compile(SectionsMap); + + for (auto &S : Sections) { + SanitizerMask Mask = 0; + +#define SANITIZER(NAME, ID) \ + if (S.SectionMatcher->match(NAME)) \ + Mask |= SanitizerKind::ID; +#define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID) + +#include "clang/Basic/Sanitizers.def" +#undef SANITIZER +#undef SANITIZER_GROUP + + SanitizerSection SS(Mask, S.Entries); + SanitizerSections.push_back(std::move(SS)); + } +} + +bool SanitizerSpecialCaseList::inSection(SanitizerMask Mask, StringRef Prefix, + StringRef Query, + StringRef Category) const { + for (auto &S : SanitizerSections) + if ((S.Mask & Mask) && + SpecialCaseList::inSection(S.Entries, Prefix, Query, Category)) + return true; + + return false; +} Index: lib/Basic/XRayLists.cpp =================================================================== --- lib/Basic/XRayLists.cpp +++ lib/Basic/XRayLists.cpp @@ -26,11 +26,13 @@ XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const { // First apply the always instrument list, than if it isn't an "always" see // whether it's treated as a "never" instrument function. - if (AlwaysInstrument->inSection("fun", FunctionName, "arg1")) + if (AlwaysInstrument->inSection("xray_always_instrument", "fun", FunctionName, + "arg1")) return ImbueAttribute::ALWAYS_ARG1; - if (AlwaysInstrument->inSection("fun", FunctionName)) + if (AlwaysInstrument->inSection("xray_always_instrument", "fun", + FunctionName)) return ImbueAttribute::ALWAYS; - if (NeverInstrument->inSection("fun", FunctionName)) + if (NeverInstrument->inSection("xray_never_instrument", "fun", FunctionName)) return ImbueAttribute::NEVER; return ImbueAttribute::NONE; } @@ -38,9 +40,11 @@ XRayFunctionFilter::ImbueAttribute XRayFunctionFilter::shouldImbueFunctionsInFile(StringRef Filename, StringRef Category) const { - if (AlwaysInstrument->inSection("src", Filename, Category)) + if (AlwaysInstrument->inSection("xray_always_instrument", "src", Filename, + Category)) return ImbueAttribute::ALWAYS; - if (NeverInstrument->inSection("src", Filename, Category)) + if (NeverInstrument->inSection("xray_never_instrument", "src", Filename, + Category)) return ImbueAttribute::NEVER; return ImbueAttribute::NONE; } Index: lib/CodeGen/CGClass.cpp =================================================================== --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2603,28 +2603,34 @@ !CGM.HasHiddenLTOVisibility(RD)) return; - std::string TypeName = RD->getQualifiedNameAsString(); - if (getContext().getSanitizerBlacklist().isBlacklistedType(TypeName)) - return; - - SanitizerScope SanScope(this); + SanitizerMask M; llvm::SanitizerStatKind SSK; switch (TCK) { case CFITCK_VCall: + M = SanitizerKind::CFIVCall; SSK = llvm::SanStat_CFI_VCall; break; case CFITCK_NVCall: + M = SanitizerKind::CFINVCall; SSK = llvm::SanStat_CFI_NVCall; break; case CFITCK_DerivedCast: + M = SanitizerKind::CFIDerivedCast; SSK = llvm::SanStat_CFI_DerivedCast; break; case CFITCK_UnrelatedCast: + M = SanitizerKind::CFIUnrelatedCast; SSK = llvm::SanStat_CFI_UnrelatedCast; break; case CFITCK_ICall: llvm_unreachable("not expecting CFITCK_ICall"); } + + std::string TypeName = RD->getQualifiedNameAsString(); + if (getContext().getSanitizerBlacklist().isBlacklistedType(M, TypeName)) + return; + + SanitizerScope SanScope(this); EmitSanitizerStatReport(SSK); llvm::Metadata *MD = @@ -2635,24 +2641,6 @@ llvm::Value *TypeTest = Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, TypeId}); - SanitizerMask M; - switch (TCK) { - case CFITCK_VCall: - M = SanitizerKind::CFIVCall; - break; - case CFITCK_NVCall: - M = SanitizerKind::CFINVCall; - break; - case CFITCK_DerivedCast: - M = SanitizerKind::CFIDerivedCast; - break; - case CFITCK_UnrelatedCast: - M = SanitizerKind::CFIUnrelatedCast; - break; - case CFITCK_ICall: - llvm_unreachable("not expecting CFITCK_ICall"); - } - llvm::Constant *StaticData[] = { llvm::ConstantInt::get(Int8Ty, TCK), EmitCheckSourceLocation(Loc), @@ -2687,7 +2675,8 @@ return false; std::string TypeName = RD->getQualifiedNameAsString(); - return !getContext().getSanitizerBlacklist().isBlacklistedType(TypeName); + return !getContext().getSanitizerBlacklist().isBlacklistedType( + SanitizerKind::CFIVCall, TypeName); } llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( Index: lib/CodeGen/CGDeclCXX.cpp =================================================================== --- lib/CodeGen/CGDeclCXX.cpp +++ lib/CodeGen/CGDeclCXX.cpp @@ -316,17 +316,23 @@ if (!getLangOpts().Exceptions) Fn->setDoesNotThrow(); - if (!isInSanitizerBlacklist(Fn, Loc)) { - if (getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address | - SanitizerKind::KernelAddress)) + SanitizerMask ASanMask = + SanitizerKind::Address | SanitizerKind::KernelAddress; + if (getLangOpts().Sanitize.hasOneOf(ASanMask)) + if (!isInSanitizerBlacklist(ASanMask, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeAddress); - if (getLangOpts().Sanitize.has(SanitizerKind::Thread)) + + if (getLangOpts().Sanitize.has(SanitizerKind::Thread)) + if (!isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); - if (getLangOpts().Sanitize.has(SanitizerKind::Memory)) + + if (getLangOpts().Sanitize.has(SanitizerKind::Memory)) + if (!isInSanitizerBlacklist(SanitizerKind::Memory, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeMemory); - if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack)) + + if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack)) + if (!isInSanitizerBlacklist(SanitizerKind::SafeStack, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SafeStack); - } return Fn; } Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -725,7 +725,7 @@ // Blacklist based on the mangled type. if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType( - Out.str())) { + SanitizerKind::Vptr, Out.str())) { llvm::hash_code TypeHash = hash_value(Out.str()); // Load the vptr, and compute hash_16_bytes(TypeHash, vptr). Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -804,8 +804,19 @@ CurFnInfo = &FnInfo; assert(CurFn->isDeclaration() && "Function already has body?"); - if (CGM.isInSanitizerBlacklist(Fn, Loc)) - SanOpts.clear(); + // If this function has been blacklisted for any of the enabled sanitizers, + // disable the sanitizer for the function. + do { +#define SANITIZER(NAME, ID) \ + if (SanOpts.empty()) \ + break; \ + if (SanOpts.has(SanitizerKind::ID)) \ + if (CGM.isInSanitizerBlacklist(SanitizerKind::ID, Fn, Loc)) \ + SanOpts.set(SanitizerKind::ID, false); + +#include "clang/Basic/Sanitizers.def" +#undef SANITIZER + } while (0); if (D) { // Apply the no_sanitize* attributes to SanOpts. Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1106,7 +1106,8 @@ /// annotations are emitted during finalization of the LLVM code. void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV); - bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const; + bool isInSanitizerBlacklist(SanitizerMask Kind, llvm::Function *Fn, + SourceLocation Loc) const; bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc, QualType Ty, Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1538,20 +1538,21 @@ Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation())); } -bool CodeGenModule::isInSanitizerBlacklist(llvm::Function *Fn, +bool CodeGenModule::isInSanitizerBlacklist(SanitizerMask Kind, + llvm::Function *Fn, SourceLocation Loc) const { const auto &SanitizerBL = getContext().getSanitizerBlacklist(); // Blacklist by function name. - if (SanitizerBL.isBlacklistedFunction(Fn->getName())) + if (SanitizerBL.isBlacklistedFunction(Kind, Fn->getName())) return true; // Blacklist by location. if (Loc.isValid()) - return SanitizerBL.isBlacklistedLocation(Loc); + return SanitizerBL.isBlacklistedLocation(Kind, 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 SanitizerBL.isBlacklistedFile(Kind, MainFile->getName()); } return false; } @@ -1560,13 +1561,14 @@ SourceLocation Loc, QualType Ty, StringRef Category) const { // For now globals can be blacklisted only in ASan and KASan. - if (!LangOpts.Sanitize.hasOneOf( - SanitizerKind::Address | SanitizerKind::KernelAddress)) + const SanitizerMask ASanMask = + SanitizerKind::Address | SanitizerKind::KernelAddress; + if (!LangOpts.Sanitize.hasOneOf(ASanMask)) return false; const auto &SanitizerBL = getContext().getSanitizerBlacklist(); - if (SanitizerBL.isBlacklistedGlobal(GV->getName(), Category)) + if (SanitizerBL.isBlacklistedGlobal(ASanMask, GV->getName(), Category)) return true; - if (SanitizerBL.isBlacklistedLocation(Loc, Category)) + if (SanitizerBL.isBlacklistedLocation(ASanMask, Loc, Category)) return true; // Check global type. if (!Ty.isNull()) { @@ -1578,7 +1580,7 @@ // We allow to blacklist only record types (classes, structs etc.) if (Ty->isRecordType()) { std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy()); - if (SanitizerBL.isBlacklistedType(TypeStr, Category)) + if (SanitizerBL.isBlacklistedType(ASanMask, TypeStr, Category)) return true; } } Index: test/CodeGen/sanitizer-special-case-list.c =================================================================== --- /dev/null +++ test/CodeGen/sanitizer-special-case-list.c @@ -0,0 +1,47 @@ +// Verify that blacklist sections correctly select sanitizers to apply blacklist entries to. +// +// RUN: echo "fun:*cfi*" > %t.unsanitized1 +// RUN: echo "fun:*overflow*" >> %t.unsanitized1 +// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%t.unsanitized1 -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED +// +// RUN: echo "[cfi]" > %t.unsanitized2 +// RUN: echo "fun:*cfi*" >> %t.unsanitized2 +// RUN: echo "[unsigned-integer-overflow]" >> %t.unsanitized2 +// RUN: echo "fun:*overflow*" >> %t.unsanitized2 +// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%t.unsanitized2 -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED +// +// RUN: echo "[cfi-icall]" > %t.unsanitized3 +// RUN: echo "fun:*cfi*" >> %t.unsanitized3 +// RUN: echo "[unsigned-integer-overflow]" >> %t.unsanitized3 +// RUN: echo "fun:*overflow*" >> %t.unsanitized3 +// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%t.unsanitized3 -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED +// +// RUN: echo "[c*]" > %t.unsanitized4 +// RUN: echo "fun:*cfi*" >> %t.unsanitized4 +// RUN: echo "[u*]" >> %t.unsanitized4 +// RUN: echo "fun:*overflow*" >> %t.unsanitized4 +// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%t.unsanitized4 -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED +// +// RUN: echo "[unsigned-integer-overflow]" > %t.sanitized +// RUN: echo "fun:*cfi*" >> %t.sanitized +// RUN: echo "[cfi]" >> %t.sanitized +// RUN: echo "fun:*overflow*" >> %t.sanitized +// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%t.sanitized -emit-llvm %s -o - | FileCheck %s --check-prefix=SANITIZED + +unsigned i; + +// SANITIZED: @overflow +// UNSANITIZED: @overflow +unsigned overflow() { + // SANITIZED: call {{.*}}void @__ubsan + // UNSANITIZED-NOT: call {{.*}}void @__ubsan + return i * 37; +} + +// SANITIZED: @cfi +// UNSANITIZED: @cfi +void cfi(void (*fp)()) { + // SANITIZED: llvm.type.test + // UNSANITIZED-NOT: llvm.type.test + fp(); +} Index: test/CodeGenCXX/cfi-blacklist.cpp =================================================================== --- test/CodeGenCXX/cfi-blacklist.cpp +++ test/CodeGenCXX/cfi-blacklist.cpp @@ -1,6 +1,18 @@ // RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s -// RUN: echo "type:std::*" > %t.txt -// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s + +// Check that blacklisting cfi and cfi-vcall work correctly +// RUN: echo "[cfi-vcall]" > %t.vcall.txt +// RUN: echo "type:std::*" >> %t.vcall.txt +// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.vcall.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s +// +// RUN: echo "[cfi]" > %t.cfi.txt +// RUN: echo "type:std::*" >> %t.cfi.txt +// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.cfi.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s + +// Check that blacklisting non-vcall modes does not affect vcalls +// RUN: echo "[cfi-icall|cfi-nvcall|cfi-cast-strict|cfi-derived-cast|cfi-unrelated-cast]" > %t.other.txt +// RUN: echo "type:std::*" >> %t.other.txt +// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.other.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s struct S1 { virtual void f();