A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
source files, functions and types using the ``src``, ``fun`` and ``type``
-entity types.
+entity types. Specific CFI modes can be be specified using ``[section]``
+headers.
.. code-block:: bash
- # Suppress checking for code in a file.
+ # Suppress all CFI checking for code in a file.
src:bad_file.cpp
src:bad_header.h
# Ignore all functions with names containing MyFooBar.
fun:*MyFooBar*
# Ignore all types in the standard library.
type:std::*
+ # Disable only unrelated cast checks for this function
+ [cfi-unrelated-cast]
+ fun:*UnrelatedCast*
+ # Disable CFI call checks for this function without affecting cast checks
+ [cfi-vcall|cfi-nvcall|cfi-icall]
+ fun:*BadCall*
+
.. _cfi-cross-dso:
Format
======
-Each line contains an entity type, followed by a colon and a regular
-expression, specifying the names of the entities, optionally followed by
-an equals sign and a tool-specific category. Empty lines and lines starting
-with "#" are ignored. The meanining of ``*`` in regular expression for entity
-names is different - it is treated as in shell wildcarding. Two generic
-entity types are ``src`` and ``fun``, which allow user to add, respectively,
-source files and functions to special case list. Some sanitizer tools may
-introduce custom entity types - refer to tool-specific docs.
+Blacklists consist of entries, optionally grouped into sections. Empty lines and
+lines starting with "#" are ignored.
+
+Section names are regular expressions written in square brackets that denote
+which sanitizer the following entries apply to. For example, ``[address]``
+specifies AddressSanitizer while ``[cfi-vcall|cfi-icall]`` specifies Control
+Flow Integrity virtual and indirect call checking. Entries without a section
+will be placed under the ``[*]`` section applying to all enabled sanitizers.
+
+Entries contain an entity type, followed by a colon and a regular expression,
+specifying the names of the entities, optionally followed by an equals sign and
+a tool-specific category, e.g. ``fun:*ExampleFunc=example_category``. The
+meaning of ``*`` in regular expression for entity names is different - it is
+treated as in shell wildcarding. Two generic entity types are ``src`` and
+``fun``, which allow users to specify source files and functions, respectively.
+Some sanitizer tools may introduce custom entity types and categories - refer to
+tool-specific docs.
.. code-block:: bash
fun:*BadFunction*
# Specific sanitizer tools may introduce categories.
src:/special/path/*=special_sources
+ # Sections can be used to limit blacklist entries to specific sanitizers
+ [address]
+ fun:*BadASanFunc*
+ # Section names are regular expressions
+ [cfi-vcall|cfi-icall]
+ fun:*BadCfiCall
+ # Entries without sections are placed into [*] and apply to all sanitizers
#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 <memory>
namespace clang {
class SanitizerBlacklist {
- std::unique_ptr<llvm::SpecialCaseList> SCL;
+ std::unique_ptr<SanitizerSpecialCaseList> SSCL;
SourceManager &SM;
public:
SanitizerBlacklist(const std::vector<std::string> &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;
};
--- /dev/null
+//===--- 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 <memory>
+
+namespace clang {
+
+class SanitizerSpecialCaseList : public llvm::SpecialCaseList {
+public:
+ static std::unique_ptr<SanitizerSpecialCaseList>
+ create(const std::vector<std::string> &Paths, std::string &Error);
+
+ static std::unique_ptr<SanitizerSpecialCaseList>
+ createOrDie(const std::vector<std::string> &Paths);
+
+ // Query blacklisted entries if any bit in Mask matches the entry's section.
+ bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query,
+ StringRef Category = StringRef()) const;
+
+protected:
+ // Initialize SanitizerSections.
+ void createSanitizerSections();
+
+ struct SanitizerSection {
+ SanitizerSection(SanitizerMask SM, SectionEntries &E)
+ : Mask(SM), Entries(E){};
+
+ SanitizerMask Mask;
+ SectionEntries &Entries;
+ };
+
+ std::vector<SanitizerSection> SanitizerSections;
+};
+
+} // end namespace clang
+
+#endif
bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().Sanitize.hasOneOf(
- SanitizerKind::Address | SanitizerKind::KernelAddress) ||
- !Context.getLangOpts().SanitizeAddressFieldPadding)
+ const SanitizerMask EnabledAsanMask = Context.getLangOpts().Sanitize.Mask &
+ (SanitizerKind::Address | SanitizerKind::KernelAddress);
+ if (!EnabledAsanMask || !Context.getLangOpts().SanitizeAddressFieldPadding)
return false;
const auto &Blacklist = Context.getSanitizerBlacklist();
const auto *CXXRD = dyn_cast<CXXRecordDecl>(this);
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(EnabledAsanMask, getLocation(),
+ "field-padding"))
ReasonToReject = 6; // is in a blacklisted file.
- else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(),
+ else if (Blacklist.isBlacklistedType(EnabledAsanMask,
+ getQualifiedNameAsString(),
"field-padding"))
ReasonToReject = 7; // is blacklisted.
OpenMPKinds.cpp
OperatorPrecedence.cpp
SanitizerBlacklist.cpp
+ SanitizerSpecialCaseList.cpp
Sanitizers.cpp
SourceLocation.cpp
SourceManager.cpp
SanitizerBlacklist::SanitizerBlacklist(
const std::vector<std::string> &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);
}
--- /dev/null
+//===--- 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>
+SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths,
+ std::string &Error) {
+ std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL(
+ new SanitizerSpecialCaseList());
+ if (SSCL->createInternal(Paths, Error)) {
+ SSCL->createSanitizerSections();
+ return SSCL;
+ }
+ return nullptr;
+}
+
+std::unique_ptr<SanitizerSpecialCaseList>
+SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
+ std::string Error;
+ if (auto SSCL = create(Paths, Error))
+ return SSCL;
+ llvm::report_fatal_error(Error);
+}
+
+void SanitizerSpecialCaseList::createSanitizerSections() {
+ 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
+
+ SanitizerSections.emplace_back(Mask, S.Entries);
+ }
+}
+
+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;
+}
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;
}
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;
}
!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 =
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),
return false;
std::string TypeName = RD->getQualifiedNameAsString();
- return !getContext().getSanitizerBlacklist().isBlacklistedType(TypeName);
+ return !getContext().getSanitizerBlacklist().isBlacklistedType(
+ SanitizerKind::CFIVCall, TypeName);
}
llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
if (!getLangOpts().Exceptions)
Fn->setDoesNotThrow();
- if (!isInSanitizerBlacklist(Fn, Loc)) {
- if (getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
- SanitizerKind::KernelAddress))
- Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
- if (getLangOpts().Sanitize.has(SanitizerKind::Thread))
- Fn->addFnAttr(llvm::Attribute::SanitizeThread);
- if (getLangOpts().Sanitize.has(SanitizerKind::Memory))
- Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
- if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack))
- Fn->addFnAttr(llvm::Attribute::SafeStack);
- }
+ if (getLangOpts().Sanitize.has(SanitizerKind::Address) &&
+ !isInSanitizerBlacklist(SanitizerKind::Address, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+
+ if (getLangOpts().Sanitize.has(SanitizerKind::KernelAddress) &&
+ !isInSanitizerBlacklist(SanitizerKind::KernelAddress, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+
+ if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
+ !isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+
+ if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
+ !isInSanitizerBlacklist(SanitizerKind::Memory, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
+
+ if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack) &&
+ !isInSanitizerBlacklist(SanitizerKind::SafeStack, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SafeStack);
return Fn;
}
// 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).
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.
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;
}
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 EnabledAsanMask = LangOpts.Sanitize.Mask &
+ (SanitizerKind::Address | SanitizerKind::KernelAddress);
+ if (!EnabledAsanMask)
return false;
const auto &SanitizerBL = getContext().getSanitizerBlacklist();
- if (SanitizerBL.isBlacklistedGlobal(GV->getName(), Category))
+ if (SanitizerBL.isBlacklistedGlobal(EnabledAsanMask, GV->getName(), Category))
return true;
- if (SanitizerBL.isBlacklistedLocation(Loc, Category))
+ if (SanitizerBL.isBlacklistedLocation(EnabledAsanMask, Loc, Category))
return true;
// Check global type.
if (!Ty.isNull()) {
// 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(EnabledAsanMask, TypeStr, Category))
return true;
}
}
/// 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,
--- /dev/null
+[unsigned-integer-overflow]
+fun:*cfi*
+[cfi]
+fun:*overflow*
--- /dev/null
+fun:*cfi*
+fun:*overflow*
--- /dev/null
+[cfi]
+fun:*cfi*
+[unsigned-integer-overflow]
+fun:*overflow*
--- /dev/null
+[cfi-icall]
+fun:*cfi*
+[unsigned-integer-overflow]
+fun:*overflow*
--- /dev/null
+[c*]
+fun:*cfi*
+[u*]
+fun:*overflow*
--- /dev/null
+// Verify that blacklist sections correctly select sanitizers to apply blacklist entries to.
+//
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized1.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized2.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized3.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized4.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+//
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.sanitized.txt -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();
+}
// 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();