summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/docs/ControlFlowIntegrity.rst62
-rw-r--r--clang/docs/ControlFlowIntegrityDesign.rst8
-rw-r--r--clang/include/clang/AST/Mangle.h3
-rw-r--r--clang/include/clang/Basic/Sanitizers.def4
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp17
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp17
-rw-r--r--clang/lib/CodeGen/CGClass.cpp7
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp23
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp38
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp20
-rw-r--r--clang/lib/Driver/ToolChain.cpp2
-rw-r--r--clang/lib/Driver/ToolChains.cpp1
-rw-r--r--clang/test/CodeGen/cfi-icall.c20
-rw-r--r--clang/test/CodeGenCXX/cfi-cast.cpp24
-rw-r--r--clang/test/CodeGenCXX/cfi-icall.cpp23
-rw-r--r--clang/test/CodeGenCXX/cfi-ms-rtti.cpp4
-rw-r--r--clang/test/CodeGenCXX/cfi-nvcall.cpp8
-rw-r--r--clang/test/CodeGenCXX/cfi-vcall.cpp70
-rw-r--r--clang/test/Driver/fsanitize.c5
19 files changed, 230 insertions, 126 deletions
diff --git a/clang/docs/ControlFlowIntegrity.rst b/clang/docs/ControlFlowIntegrity.rst
index b043d24a142..b583fc0debc 100644
--- a/clang/docs/ControlFlowIntegrity.rst
+++ b/clang/docs/ControlFlowIntegrity.rst
@@ -20,12 +20,14 @@ program's control flow. These schemes have been optimized for performance,
allowing developers to enable them in release builds.
To enable Clang's available CFI schemes, use the flag ``-fsanitize=cfi``.
-As currently implemented, CFI relies on link-time optimization (LTO); so it is
-required to specify ``-flto``, and the linker used must support LTO, for example
-via the `gold plugin`_. To allow the checks to be implemented efficiently,
-the program must be structured such that certain object files are compiled
-with CFI enabled, and are statically linked into the program. This may
-preclude the use of shared libraries in some cases.
+As currently implemented, all of Clang's CFI schemes (``cfi-vcall``,
+``cfi-derived-cast``, ``cfi-unrelated-cast``, ``cfi-nvcall``, ``cfi-icall``)
+rely on link-time optimization (LTO); so it is required to specify
+``-flto``, and the linker used must support LTO, for example via the `gold
+plugin`_. To allow the checks to be implemented efficiently, the program must
+be structured such that certain object files are compiled with CFI enabled,
+and are statically linked into the program. This may preclude the use of
+shared libraries in some cases.
Clang currently implements forward-edge CFI for member function calls and
bad cast checking. More schemes are under development.
@@ -123,6 +125,54 @@ member functions on class instances with specific properties that works under
most compilers and should not have security implications, so we allow it by
default. It can be disabled with ``-fsanitize=cfi-cast-strict``.
+Indirect Function Call Checking
+-------------------------------
+
+This scheme checks that function calls take place using a function of the
+correct dynamic type; that is, the dynamic type of the function must match
+the static type used at the call. This CFI scheme can be enabled on its own
+using ``-fsanitize=cfi-icall``.
+
+For this scheme to work, each indirect function call in the program, other
+than calls in :ref:`blacklisted <cfi-blacklist>` functions, must call a
+function which was either compiled with ``-fsanitize=cfi-icall`` enabled,
+or whose address was taken by a function in a translation unit compiled with
+``-fsanitize=cfi-icall``.
+
+If a function in a translation unit compiled with ``-fsanitize=cfi-icall``
+takes the address of a function not compiled with ``-fsanitize=cfi-icall``,
+that address may differ from the address taken by a function in a translation
+unit not compiled with ``-fsanitize=cfi-icall``. This is technically a
+violation of the C and C++ standards, but it should not affect most programs.
+
+Each translation unit compiled with ``-fsanitize=cfi-icall`` must be
+statically linked into the program or shared library, and calls across
+shared library boundaries are handled as if the callee was not compiled with
+``-fsanitize=cfi-icall``.
+
+This scheme is currently only supported on the x86 and x86_64 architectures.
+
+``-fsanitize=cfi-icall`` and ``-fsanitize=function``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This tool is similar to ``-fsanitize=function`` in that both tools check
+the types of function calls. However, the two tools occupy different points
+on the design space; ``-fsanitize=function`` is a developer tool designed
+to find bugs in local development builds, whereas ``-fsanitize=cfi-icall``
+is a security hardening mechanism designed to be deployed in release builds.
+
+``-fsanitize=function`` has a higher space and time overhead due to a more
+complex type check at indirect call sites, as well as a need for run-time
+type information (RTTI), which may make it unsuitable for deployment. Because
+of the need for RTTI, ``-fsanitize=function`` can only be used with C++
+programs, whereas ``-fsanitize=cfi-icall`` can protect both C and C++ programs.
+
+On the other hand, ``-fsanitize=function`` conforms more closely with the C++
+standard and user expectations around interaction with shared libraries;
+the identity of function pointers is maintained, and calls across shared
+library boundaries are no different from calls within a single program or
+shared library.
+
.. _cfi-blacklist:
Blacklist
diff --git a/clang/docs/ControlFlowIntegrityDesign.rst b/clang/docs/ControlFlowIntegrityDesign.rst
index 89aa038d003..af3744576d7 100644
--- a/clang/docs/ControlFlowIntegrityDesign.rst
+++ b/clang/docs/ControlFlowIntegrityDesign.rst
@@ -273,3 +273,11 @@ Eliminating Bit Vector Checks for All-Ones Bit Vectors
If the bit vector is all ones, the bit vector check is redundant; we simply
need to check that the address is in range and well aligned. This is more
likely to occur if the virtual tables are padded.
+
+Forward-Edge CFI for Indirect Function Calls
+============================================
+
+Sorry, no documentation yet, but see the comments at the top of
+``LowerBitSets::buildBitSetsFromFunctions`` in `LowerBitSets.cpp`_.
+
+.. _LowerBitSets.cpp: http://llvm.org/klaus/llvm/blob/master/lib/Transforms/IPO/LowerBitSets.cpp
diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h
index 735ae11a233..7b725b65ca1 100644
--- a/clang/include/clang/AST/Mangle.h
+++ b/clang/include/clang/AST/Mangle.h
@@ -144,9 +144,6 @@ public:
/// across translation units so it can be used with LTO.
virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
- virtual void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
- raw_ostream &) = 0;
-
/// @}
};
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index 1b528c8d6f6..4b685936291 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -84,11 +84,13 @@ SANITIZER("dataflow", DataFlow)
// Control Flow Integrity
SANITIZER("cfi-cast-strict", CFICastStrict)
SANITIZER("cfi-derived-cast", CFIDerivedCast)
+SANITIZER("cfi-icall", CFIICall)
SANITIZER("cfi-unrelated-cast", CFIUnrelatedCast)
SANITIZER("cfi-nvcall", CFINVCall)
SANITIZER("cfi-vcall", CFIVCall)
SANITIZER_GROUP("cfi", CFI,
- CFIDerivedCast | CFIUnrelatedCast | CFINVCall | CFIVCall)
+ CFIDerivedCast | CFIICall | CFIUnrelatedCast | CFINVCall |
+ CFIVCall)
// Safe Stack
SANITIZER("safe-stack", SafeStack)
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 3f40743d9b4..774ef9ae352 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -174,8 +174,6 @@ public:
void mangleStringLiteral(const StringLiteral *, raw_ostream &) override;
- void mangleCXXVTableBitSet(const CXXRecordDecl *RD, raw_ostream &) override;
-
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
if (isLambda(ND))
@@ -4098,21 +4096,6 @@ void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) {
mangleCXXRTTIName(Ty, Out);
}
-void ItaniumMangleContextImpl::mangleCXXVTableBitSet(const CXXRecordDecl *RD,
- raw_ostream &Out) {
- if (!RD->isExternallyVisible()) {
- // This part of the identifier needs to be unique across all translation
- // units in the linked program. The scheme fails if multiple translation
- // units are compiled using the same relative source file path, or if
- // multiple translation units are built from the same source file.
- SourceManager &SM = getASTContext().getSourceManager();
- Out << "[" << SM.getFileEntryForID(SM.getMainFileID())->getName() << "]";
- }
-
- CXXNameMangler Mangler(*this, Out);
- Mangler.mangleType(QualType(RD->getTypeForDecl(), 0));
-}
-
void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_ostream &) {
llvm_unreachable("Can't mangle string literals");
}
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index dd6e952bbae..fcd7a4ab1ed 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -161,8 +161,6 @@ public:
void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
- void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
- raw_ostream &Out) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
if (isLambda(ND))
@@ -2776,21 +2774,6 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
Mangler.getStream() << '@';
}
-void MicrosoftMangleContextImpl::mangleCXXVTableBitSet(const CXXRecordDecl *RD,
- raw_ostream &Out) {
- if (!RD->isExternallyVisible()) {
- // This part of the identifier needs to be unique across all translation
- // units in the linked program. The scheme fails if multiple translation
- // units are compiled using the same relative source file path, or if
- // multiple translation units are built from the same source file.
- SourceManager &SM = getASTContext().getSourceManager();
- Out << "[" << SM.getFileEntryForID(SM.getMainFileID())->getName() << "]";
- }
-
- MicrosoftCXXNameMangler mangler(*this, Out);
- mangler.mangleName(RD);
-}
-
MicrosoftMangleContext *
MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new MicrosoftMangleContextImpl(Context, Diags);
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index dc65b14a91f..56787e5de26 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2473,12 +2473,9 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
SanitizerScope SanScope(this);
- std::string OutName;
- llvm::raw_string_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXVTableBitSet(RD, Out);
-
llvm::Value *BitSetName = llvm::MetadataAsValue::get(
- getLLVMContext(), llvm::MDString::get(getLLVMContext(), Out.str()));
+ getLLVMContext(),
+ CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)));
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
llvm::Value *BitSetTest =
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 8339444c20e..5e6c4de4087 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3780,6 +3780,29 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
}
}
+ // If we are checking indirect calls and this call is indirect, check that the
+ // function pointer is a member of the bit set for the function type.
+ if (SanOpts.has(SanitizerKind::CFIICall) &&
+ (!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
+ SanitizerScope SanScope(this);
+
+ llvm::Value *BitSetName = llvm::MetadataAsValue::get(
+ getLLVMContext(),
+ CGM.CreateMetadataIdentifierForType(QualType(FnType, 0)));
+
+ llvm::Value *CastedCallee = Builder.CreateBitCast(Callee, Int8PtrTy);
+ llvm::Value *BitSetTest =
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
+ {CastedCallee, BitSetName});
+
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(E->getLocStart()),
+ EmitCheckTypeDescriptor(QualType(FnType, 0)),
+ };
+ EmitCheck(std::make_pair(BitSetTest, SanitizerKind::CFIICall),
+ "cfi_bad_icall", StaticData, CastedCallee);
+ }
+
CallArgList Args;
if (Chain)
Args.add(RValue::get(Builder.CreateBitCast(Chain, CGM.VoidPtrTy)),
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index 6aa624ec060..4c3202ca656 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -893,41 +893,45 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
CharUnits PointerWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- std::vector<llvm::MDTuple *> BitsetEntries;
+ typedef std::pair<const CXXRecordDecl *, unsigned> BSEntry;
+ std::vector<BSEntry> BitsetEntries;
// Create a bit set entry for each address point.
for (auto &&AP : VTLayout.getAddressPoints()) {
if (IsCFIBlacklistedRecord(AP.first.getBase()))
continue;
- BitsetEntries.push_back(CreateVTableBitSetEntry(
- VTable, PointerWidth * AP.second, AP.first.getBase()));
+ BitsetEntries.push_back(std::make_pair(AP.first.getBase(), AP.second));
}
// Sort the bit set entries for determinism.
- std::sort(BitsetEntries.begin(), BitsetEntries.end(), [](llvm::MDTuple *T1,
- llvm::MDTuple *T2) {
- if (T1 == T2)
+ std::sort(BitsetEntries.begin(), BitsetEntries.end(),
+ [this](const BSEntry &E1, const BSEntry &E2) {
+ if (&E1 == &E2)
return false;
- StringRef S1 = cast<llvm::MDString>(T1->getOperand(0))->getString();
- StringRef S2 = cast<llvm::MDString>(T2->getOperand(0))->getString();
+ std::string S1;
+ llvm::raw_string_ostream O1(S1);
+ getCXXABI().getMangleContext().mangleTypeName(
+ QualType(E1.first->getTypeForDecl(), 0), O1);
+ O1.flush();
+
+ std::string S2;
+ llvm::raw_string_ostream O2(S2);
+ getCXXABI().getMangleContext().mangleTypeName(
+ QualType(E2.first->getTypeForDecl(), 0), O2);
+ O2.flush();
+
if (S1 < S2)
return true;
if (S1 != S2)
return false;
- uint64_t Offset1 = cast<llvm::ConstantInt>(
- cast<llvm::ConstantAsMetadata>(T1->getOperand(2))
- ->getValue())->getZExtValue();
- uint64_t Offset2 = cast<llvm::ConstantInt>(
- cast<llvm::ConstantAsMetadata>(T2->getOperand(2))
- ->getValue())->getZExtValue();
- assert(Offset1 != Offset2);
- return Offset1 < Offset2;
+ return E1.second < E2.second;
});
llvm::NamedMDNode *BitsetsMD =
getModule().getOrInsertNamedMetadata("llvm.bitsets");
for (auto BitsetEntry : BitsetEntries)
- BitsetsMD->addOperand(BitsetEntry);
+ BitsetsMD->addOperand(CreateVTableBitSetEntry(
+ VTable, PointerWidth * BitsetEntry.second, BitsetEntry.first));
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index a2d554bde54..8f0259d502a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -941,6 +941,20 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
if (FD->isReplaceableGlobalAllocationFunction())
F->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoBuiltin);
+
+ // If we are checking indirect calls and this is not a non-static member
+ // function, emit a bit set entry for the function type.
+ if (LangOpts.Sanitize.has(SanitizerKind::CFIICall) &&
+ !(isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())) {
+ llvm::NamedMDNode *BitsetsMD =
+ getModule().getOrInsertNamedMetadata("llvm.bitsets");
+
+ llvm::Metadata *BitsetOps[] = {
+ CreateMetadataIdentifierForType(FD->getType()),
+ llvm::ConstantAsMetadata::get(F),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))};
+ BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
+ }
}
void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {
@@ -3824,12 +3838,8 @@ llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) {
llvm::MDTuple *CodeGenModule::CreateVTableBitSetEntry(
llvm::GlobalVariable *VTable, CharUnits Offset, const CXXRecordDecl *RD) {
- std::string OutName;
- llvm::raw_string_ostream Out(OutName);
- getCXXABI().getMangleContext().mangleCXXVTableBitSet(RD, Out);
-
llvm::Metadata *BitsetOps[] = {
- llvm::MDString::get(getLLVMContext(), Out.str()),
+ CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)),
llvm::ConstantAsMetadata::get(VTable),
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index e034f72a265..e93487d28c2 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -495,6 +495,6 @@ SanitizerMask ToolChain::getSupportedSanitizers() const {
// Return sanitizers which don't require runtime support and are not
// platform or architecture-dependent.
using namespace SanitizerKind;
- return (Undefined & ~Vptr & ~Function) | CFI | CFICastStrict |
+ return (Undefined & ~Vptr & ~Function) | (CFI & ~CFIICall) | CFICastStrict |
UnsignedIntegerOverflow | LocalBounds;
}
diff --git a/clang/lib/Driver/ToolChains.cpp b/clang/lib/Driver/ToolChains.cpp
index 7f0b9bb7472..c3f9b5876d7 100644
--- a/clang/lib/Driver/ToolChains.cpp
+++ b/clang/lib/Driver/ToolChains.cpp
@@ -3764,6 +3764,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
if (IsX86_64 || IsMIPS64 || IsPowerPC64)
Res |= SanitizerKind::Memory;
if (IsX86 || IsX86_64) {
+ Res |= SanitizerKind::CFIICall;
Res |= SanitizerKind::Function;
Res |= SanitizerKind::SafeStack;
}
diff --git a/clang/test/CodeGen/cfi-icall.c b/clang/test/CodeGen/cfi-icall.c
new file mode 100644
index 00000000000..d6cebef49a1
--- /dev/null
+++ b/clang/test/CodeGen/cfi-icall.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=MS %s
+
+// Tests that we assign appropriate identifiers to unprototyped functions.
+
+void f() {
+}
+
+void xf();
+
+void g(int b) {
+ void (*fp)() = b ? f : xf;
+ // ITANIUM: call i1 @llvm.bitset.test(i8* {{.*}}, metadata !"_ZTSFvE")
+ fp();
+}
+
+// ITANIUM-DAG: !{!"_ZTSFvE", void ()* @f, i64 0}
+// ITANIUM-DAG: !{!"_ZTSFvE", void (...)* @xf, i64 0}
+// MS-DAG: !{!"?6AX@Z", void ()* @f, i64 0}
+// MS-DAG: !{!"?6AX@Z", void (...)* @xf, i64 0}
diff --git a/clang/test/CodeGenCXX/cfi-cast.cpp b/clang/test/CodeGenCXX/cfi-cast.cpp
index 7efcd9e0cae..0b96cb6506c 100644
--- a/clang/test/CodeGenCXX/cfi-cast.cpp
+++ b/clang/test/CodeGenCXX/cfi-cast.cpp
@@ -18,7 +18,7 @@ struct C : A {};
// CHECK-DCAST-LABEL: define void @_Z3abpP1A
void abp(A *a) {
- // CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ // CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-DCAST: [[TRAPBB]]
@@ -32,7 +32,7 @@ void abp(A *a) {
// CHECK-DCAST-LABEL: define void @_Z3abrR1A
void abr(A &a) {
- // CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ // CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-DCAST: [[TRAPBB]]
@@ -46,7 +46,7 @@ void abr(A &a) {
// CHECK-DCAST-LABEL: define void @_Z4abrrO1A
void abrr(A &&a) {
- // CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ // CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-DCAST: [[TRAPBB]]
@@ -60,7 +60,7 @@ void abrr(A &&a) {
// CHECK-UCAST-LABEL: define void @_Z3vbpPv
void vbp(void *p) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-UCAST: [[TRAPBB]]
@@ -74,7 +74,7 @@ void vbp(void *p) {
// CHECK-UCAST-LABEL: define void @_Z3vbrRc
void vbr(char &r) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-UCAST: [[TRAPBB]]
@@ -88,7 +88,7 @@ void vbr(char &r) {
// CHECK-UCAST-LABEL: define void @_Z4vbrrOc
void vbrr(char &&r) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-UCAST: [[TRAPBB]]
@@ -103,23 +103,23 @@ void vbrr(char &&r) {
// CHECK-UCAST-LABEL: define void @_Z3vcpPv
// CHECK-UCAST-STRICT-LABEL: define void @_Z3vcpPv
void vcp(void *p) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1A")
- // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1C")
+ // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
+ // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
static_cast<C*>(p);
}
// CHECK-UCAST-LABEL: define void @_Z3bcpP1B
// CHECK-UCAST-STRICT-LABEL: define void @_Z3bcpP1B
void bcp(B *p) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1A")
- // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1C")
+ // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
+ // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
(C *)p;
}
// CHECK-UCAST-LABEL: define void @_Z8bcp_callP1B
// CHECK-UCAST-STRICT-LABEL: define void @_Z8bcp_callP1B
void bcp_call(B *p) {
- // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1A")
- // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1C")
+ // CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
+ // CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
((C *)p)->f();
}
diff --git a/clang/test/CodeGenCXX/cfi-icall.cpp b/clang/test/CodeGenCXX/cfi-icall.cpp
new file mode 100644
index 00000000000..eceb92a4421
--- /dev/null
+++ b/clang/test/CodeGenCXX/cfi-icall.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
+
+// Tests that we assign unnamed metadata nodes to functions whose types have
+// internal linkage.
+
+namespace {
+
+struct S {};
+
+void f(S *s) {
+}
+
+}
+
+void g() {
+ void (*fp)(S *) = f;
+ // CHECK: call i1 @llvm.bitset.test(i8* {{.*}}, metadata ![[VOIDS:[0-9]+]])
+ fp(0);
+}
+
+// ITANIUM: !{![[VOIDS]], void (%"struct.(anonymous namespace)::S"*)* @_ZN12_GLOBAL__N_11fEPNS_1SE, i64 0}
+// MS: !{![[VOIDS]], void (%"struct.(anonymous namespace)::S"*)* @"\01?f@?A@@YAXPEAUS@?A@@@Z", i64 0}
diff --git a/clang/test/CodeGenCXX/cfi-ms-rtti.cpp b/clang/test/CodeGenCXX/cfi-ms-rtti.cpp
index 5203a6bb0c8..b6e9175c865 100644
--- a/clang/test/CodeGenCXX/cfi-ms-rtti.cpp
+++ b/clang/test/CodeGenCXX/cfi-ms-rtti.cpp
@@ -8,5 +8,5 @@ struct A {
A::A() {}
-// RTTI: !{!"A@@", [2 x i8*]* {{.*}}, i64 8}
-// NO-RTTI: !{!"A@@", [1 x i8*]* {{.*}}, i64 0}
+// RTTI: !{!"?AUA@@", [2 x i8*]* {{.*}}, i64 8}
+// NO-RTTI: !{!"?AUA@@", [1 x i8*]* {{.*}}, i64 0}
diff --git a/clang/test/CodeGenCXX/cfi-nvcall.cpp b/clang/test/CodeGenCXX/cfi-nvcall.cpp
index b0db478c9d0..be4d8448a2e 100644
--- a/clang/test/CodeGenCXX/cfi-nvcall.cpp
+++ b/clang/test/CodeGenCXX/cfi-nvcall.cpp
@@ -17,8 +17,8 @@ struct C : A {
// CHECK-LABEL: @bg
// CHECK-STRICT-LABEL: @bg
extern "C" void bg(B *b) {
- // CHECK: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
- // CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ // CHECK: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
+ // CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
b->g();
}
@@ -29,7 +29,7 @@ extern "C" void cg(C *c) {
// In this case C's layout is the same as its base class, so we allow
// c to be of type A in non-strict mode.
- // CHECK: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1A")
- // CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1C")
+ // CHECK: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
+ // CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
c->g();
}
diff --git a/clang/test/CodeGenCXX/cfi-vcall.cpp b/clang/test/CodeGenCXX/cfi-vcall.cpp
index 5cb5e02cf58..daa0531e85d 100644
--- a/clang/test/CodeGenCXX/cfi-vcall.cpp
+++ b/clang/test/CodeGenCXX/cfi-vcall.cpp
@@ -60,8 +60,8 @@ void D::h() {
// ITANIUM: define void @_Z2afP1A
// MS: define void @"\01?af@@YAXPEAUA@@@Z"
void af(A *a) {
- // ITANIUM: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"1A")
- // MS: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"A@@")
+ // ITANIUM: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A")
+ // MS: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"?AUA@@")
// CHECK-NEXT: br i1 [[P]], label %[[CONTBB:[^ ,]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-NEXT: {{^$}}
@@ -82,24 +82,24 @@ void af(A *a) {
// ITANIUM: define internal void @_Z3df1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?df1@@YAXPEAUD@?A@@@Z"
void df1(D *d) {
- // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"[{{.*}}cfi-vcall.cpp]N12_GLOBAL__N_11DE")
- // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"A@@")
+ // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
+ // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"?AUA@@")
d->f();
}
// ITANIUM: define internal void @_Z3dg1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?dg1@@YAXPEAUD@?A@@@Z"
void dg1(D *d) {
- // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
- // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"B@@")
+ // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
+ // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"?AUB@@")
d->g();
}
// ITANIUM: define internal void @_Z3dh1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?dh1@@YAXPEAUD@?A@@@Z"
void dh1(D *d) {
- // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"[{{.*}}cfi-vcall.cpp]N12_GLOBAL__N_11DE")
- // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"[{{.*}}cfi-vcall.cpp]D@?A@@")
+ // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata ![[DTYPE]])
+ // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
d->h();
}
@@ -150,8 +150,8 @@ struct D : C {
// ITANIUM: define void @_ZN5test21fEPNS_1DE
// MS: define void @"\01?f@test2@@YAXPEAUD@1@@Z"
void f(D *d) {
- // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"N5test21DE")
- // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"A@test2@@")
+ // ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
+ // MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"?AUA@test2@@")
d->m_fn1();
}
@@ -161,28 +161,28 @@ void f(D *d) {
// MS: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){8}]]}
// ITANIUM: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){14}]]}
-// ITANIUM-DAG: !{!"1A", [3 x i8*]* @_ZTV1A, i64 16}
-// ITANIUM-DAG: !{!"1A", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
-// ITANIUM-DAG: !{!"1B", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
-// ITANIUM-DAG: !{!"1A", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 64}
-// ITANIUM-DAG: !{!"1C", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 32}
-// ITANIUM-DAG: !{!"1A", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
-// ITANIUM-DAG: !{!"1B", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
-// ITANIUM-DAG: !{!"1C", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 88}
-// ITANIUM-DAG: !{!"[{{.*}}cfi-vcall.cpp]N12_GLOBAL__N_11DE", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
-// ITANIUM-DAG: !{!"1A", [7 x i8*]* @_ZTV1B, i64 32}
-// ITANIUM-DAG: !{!"1B", [7 x i8*]* @_ZTV1B, i64 32}
-// ITANIUM-DAG: !{!"1A", [5 x i8*]* @_ZTV1C, i64 32}
-// ITANIUM-DAG: !{!"1C", [5 x i8*]* @_ZTV1C, i64 32}
-// ITANIUM-DAG: !{!"1A", [3 x i8*]* @_ZTVZ3foovE2FA, i64 16}
-// ITANIUM-DAG: !{!"[{{.*}}cfi-vcall.cpp]Z3foovE2FA", [3 x i8*]* @_ZTVZ3foovE2FA, i64 16}
-
-// MS-DAG: !{!"A@@", [2 x i8*]* @[[VTA]], i64 8}
-// MS-DAG: !{!"B@@", [3 x i8*]* @[[VTB]], i64 8}
-// MS-DAG: !{!"A@@", [2 x i8*]* @[[VTAinB]], i64 8}
-// MS-DAG: !{!"A@@", [2 x i8*]* @[[VTAinC]], i64 8}
-// MS-DAG: !{!"B@@", [3 x i8*]* @[[VTBinD]], i64 8}
-// MS-DAG: !{!"[{{.*}}cfi-vcall.cpp]D@?A@@", [3 x i8*]* @[[VTBinD]], i64 8}
-// MS-DAG: !{!"A@@", [2 x i8*]* @[[VTAinBinD]], i64 8}
-// MS-DAG: !{!"A@@", [2 x i8*]* @[[VTFA]], i64 8}
-// MS-DAG: !{!"[{{.*}}cfi-vcall.cpp]FA@?1??foo@@YAXXZ@", [2 x i8*]* @[[VTFA]], i64 8}
+// ITANIUM-DAG: !{!"_ZTS1A", [3 x i8*]* @_ZTV1A, i64 16}
+// ITANIUM-DAG: !{!"_ZTS1A", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1B", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1A", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 64}
+// ITANIUM-DAG: !{!"_ZTS1C", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1A", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1B", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1C", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 88}
+// ITANIUM-DAG: !{![[DTYPE]], [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1A", [7 x i8*]* @_ZTV1B, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1B", [7 x i8*]* @_ZTV1B, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1A", [5 x i8*]* @_ZTV1C, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1C", [5 x i8*]* @_ZTV1C, i64 32}
+// ITANIUM-DAG: !{!"_ZTS1A", [3 x i8*]* @_ZTVZ3foovE2FA, i64 16}
+// ITANIUM-DAG: !{!{{[0-9]+}}, [3 x i8*]* @_ZTVZ3foovE2FA, i64 16}
+
+// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTA]], i64 8}
+// MS-DAG: !{!"?AUB@@", [3 x i8*]* @[[VTB]], i64 8}
+// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinB]], i64 8}
+// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinC]], i64 8}
+// MS-DAG: !{!"?AUB@@", [3 x i8*]* @[[VTBinD]], i64 8}
+// MS-DAG: !{![[DTYPE]], [3 x i8*]* @[[VTBinD]], i64 8}
+// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinBinD]], i64 8}
+// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTFA]], i64 8}
+// MS-DAG: !{!{{[0-9]+}}, [2 x i8*]* @[[VTFA]], i64 8}
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index 15b43833273..ce140e58c96 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -234,7 +234,7 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-unrelated-cast -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-UCAST
// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-nvcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NVCALL
// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-vcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-VCALL
-// CHECK-CFI: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast,cfi-unrelated-cast,cfi-nvcall,cfi-vcall
+// CHECK-CFI: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast,cfi-icall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall
// CHECK-CFI-DCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast
// CHECK-CFI-UCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-unrelated-cast
// CHECK-CFI-NVCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-nvcall
@@ -243,6 +243,9 @@
// RUN: %clang -target x86_64-linux-gnu -flto -fsanitize=cfi-derived-cast -fno-lto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOLTO
// CHECK-CFI-NOLTO: '-fsanitize=cfi-derived-cast' only allowed with '-flto'
+// RUN: %clang -target mips-unknown-linux -fsanitize=cfi-icall %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-ICALL-MIPS
+// CHECK-CFI-ICALL-MIPS: unsupported option '-fsanitize=cfi-icall' for target 'mips-unknown-linux'
+
// RUN: %clang -target x86_64-linux-gnu -fsanitize-trap=address -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TRAP
// CHECK-ASAN-TRAP: error: unsupported argument 'address' to option '-fsanitize-trap'
OpenPOWER on IntegriCloud