mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-01 13:20:25 +00:00
CodeGen: Update Clang to use the new type metadata.
Differential Revision: http://reviews.llvm.org/D21054 llvm-svn: 273730
This commit is contained in:
parent
7efd750607
commit
8dd14da0dc
@ -90,10 +90,10 @@ For example on x86 a typical virtual call may look like this:
|
||||
|
||||
The compiler relies on co-operation from the linker in order to assemble
|
||||
the bit vectors for the whole program. It currently does this using LLVM's
|
||||
`bit sets`_ mechanism together with link-time optimization.
|
||||
`type metadata`_ mechanism together with link-time optimization.
|
||||
|
||||
.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general
|
||||
.. _bit sets: http://llvm.org/docs/BitSets.html
|
||||
.. _type metadata: http://llvm.org/docs/TypeMetadata.html
|
||||
.. _ByteArrayBuilder: http://llvm.org/docs/doxygen/html/structllvm_1_1ByteArrayBuilder.html
|
||||
|
||||
Optimizations
|
||||
@ -196,7 +196,7 @@ those sub-hierarchies need to be (see "Stripping Leading/Trailing Zeros in Bit
|
||||
Vectors" above). The `GlobalLayoutBuilder`_ class is responsible for laying
|
||||
out the globals efficiently to minimize the sizes of the underlying bitsets.
|
||||
|
||||
.. _GlobalLayoutBuilder: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/LowerBitSets.h?view=markup
|
||||
.. _GlobalLayoutBuilder: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/LowerTypeTests.h?view=markup
|
||||
|
||||
Alignment
|
||||
~~~~~~~~~
|
||||
@ -297,8 +297,8 @@ file's symbol table, the symbols for the target functions also refer to the
|
||||
jump table entries, so that addresses taken outside the module will pass
|
||||
any verification done inside the module.
|
||||
|
||||
In more concrete terms, suppose we have three functions ``f``, ``g``, ``h``
|
||||
which are members of a single bitset, and a function foo that returns their
|
||||
In more concrete terms, suppose we have three functions ``f``, ``g``,
|
||||
``h`` which are all of the same type, and a function foo that returns their
|
||||
addresses:
|
||||
|
||||
.. code-block:: none
|
||||
@ -439,10 +439,10 @@ export this information, every DSO implements
|
||||
|
||||
void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr)
|
||||
|
||||
This function provides external modules with access to CFI checks for
|
||||
the targets inside this DSO. For each known ``CallSiteTypeId``, this
|
||||
functions performs an ``llvm.bitset.test`` with the corresponding bit
|
||||
set. It aborts if the type is unknown, or if the check fails.
|
||||
This function provides external modules with access to CFI checks for the
|
||||
targets inside this DSO. For each known ``CallSiteTypeId``, this function
|
||||
performs an ``llvm.type.test`` with the corresponding type identifier. It
|
||||
aborts if the type is unknown, or if the check fails.
|
||||
|
||||
The basic implementation is a large switch statement over all values
|
||||
of CallSiteTypeId supported by this DSO, and each case is similar to
|
||||
|
@ -2485,21 +2485,21 @@ LeastDerivedClassWithSameLayout(const CXXRecordDecl *RD) {
|
||||
RD->bases_begin()->getType()->getAsCXXRecordDecl());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitBitSetCodeForVCall(const CXXRecordDecl *RD,
|
||||
llvm::Value *VTable,
|
||||
SourceLocation Loc) {
|
||||
void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
|
||||
llvm::Value *VTable,
|
||||
SourceLocation Loc) {
|
||||
if (CGM.getCodeGenOpts().WholeProgramVTables &&
|
||||
CGM.HasHiddenLTOVisibility(RD)) {
|
||||
llvm::Metadata *MD =
|
||||
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
|
||||
llvm::Value *BitSetName =
|
||||
llvm::Value *TypeId =
|
||||
llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
|
||||
|
||||
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
|
||||
llvm::Value *BitSetTest =
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
|
||||
{CastedVTable, BitSetName});
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), BitSetTest);
|
||||
llvm::Value *TypeTest =
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
|
||||
{CastedVTable, TypeId});
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
|
||||
}
|
||||
|
||||
if (SanOpts.has(SanitizerKind::CFIVCall))
|
||||
@ -2595,12 +2595,11 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
|
||||
|
||||
llvm::Metadata *MD =
|
||||
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
|
||||
llvm::Value *BitSetName = llvm::MetadataAsValue::get(getLLVMContext(), MD);
|
||||
llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);
|
||||
|
||||
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
|
||||
llvm::Value *BitSetTest =
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
|
||||
{CastedVTable, BitSetName});
|
||||
llvm::Value *TypeTest = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, TypeId});
|
||||
|
||||
SanitizerMask M;
|
||||
switch (TCK) {
|
||||
@ -2626,24 +2625,23 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
|
||||
EmitCheckTypeDescriptor(QualType(RD->getTypeForDecl(), 0)),
|
||||
};
|
||||
|
||||
auto TypeId = CGM.CreateCfiIdForTypeMetadata(MD);
|
||||
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && TypeId) {
|
||||
EmitCfiSlowPathCheck(M, BitSetTest, TypeId, CastedVTable, StaticData);
|
||||
auto CrossDsoTypeId = CGM.CreateCrossDsoCfiTypeId(MD);
|
||||
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && CrossDsoTypeId) {
|
||||
EmitCfiSlowPathCheck(M, TypeTest, CrossDsoTypeId, CastedVTable, StaticData);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CGM.getCodeGenOpts().SanitizeTrap.has(M)) {
|
||||
EmitTrapCheck(BitSetTest);
|
||||
EmitTrapCheck(TypeTest);
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::Value *AllVtables = llvm::MetadataAsValue::get(
|
||||
CGM.getLLVMContext(),
|
||||
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
|
||||
llvm::Value *ValidVtable =
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
|
||||
{CastedVTable, AllVtables});
|
||||
EmitCheck(std::make_pair(BitSetTest, M), "cfi_check_fail", StaticData,
|
||||
llvm::Value *ValidVtable = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, AllVtables});
|
||||
EmitCheck(std::make_pair(TypeTest, M), "cfi_check_fail", StaticData,
|
||||
{CastedVTable, ValidVtable});
|
||||
}
|
||||
|
||||
|
@ -2682,7 +2682,7 @@ void CodeGenFunction::EmitCfiCheckFail() {
|
||||
CGM.getLLVMContext(),
|
||||
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
|
||||
llvm::Value *ValidVtable = Builder.CreateZExt(
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
|
||||
{Addr, AllVtables}),
|
||||
IntPtrTy);
|
||||
|
||||
@ -4050,24 +4050,23 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
|
||||
EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
|
||||
|
||||
llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
|
||||
llvm::Value *BitSetName = llvm::MetadataAsValue::get(getLLVMContext(), MD);
|
||||
llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);
|
||||
|
||||
llvm::Value *CastedCallee = Builder.CreateBitCast(Callee, Int8PtrTy);
|
||||
llvm::Value *BitSetTest =
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
|
||||
{CastedCallee, BitSetName});
|
||||
llvm::Value *TypeTest = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedCallee, TypeId});
|
||||
|
||||
auto TypeId = CGM.CreateCfiIdForTypeMetadata(MD);
|
||||
auto CrossDsoTypeId = CGM.CreateCrossDsoCfiTypeId(MD);
|
||||
llvm::Constant *StaticData[] = {
|
||||
llvm::ConstantInt::get(Int8Ty, CFITCK_ICall),
|
||||
EmitCheckSourceLocation(E->getLocStart()),
|
||||
EmitCheckTypeDescriptor(QualType(FnType, 0)),
|
||||
};
|
||||
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && TypeId) {
|
||||
EmitCfiSlowPathCheck(SanitizerKind::CFIICall, BitSetTest, TypeId,
|
||||
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && CrossDsoTypeId) {
|
||||
EmitCfiSlowPathCheck(SanitizerKind::CFIICall, TypeTest, CrossDsoTypeId,
|
||||
CastedCallee, StaticData);
|
||||
} else {
|
||||
EmitCheck(std::make_pair(BitSetTest, SanitizerKind::CFIICall),
|
||||
EmitCheck(std::make_pair(TypeTest, SanitizerKind::CFIICall),
|
||||
"cfi_check_fail", StaticData,
|
||||
{CastedCallee, llvm::UndefValue::get(IntPtrTy)});
|
||||
}
|
||||
|
@ -709,7 +709,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
|
||||
VTLayout->getNumVTableThunks(), RTTI);
|
||||
VTable->setInitializer(Init);
|
||||
|
||||
CGM.EmitVTableBitSetEntries(VTable, *VTLayout.get());
|
||||
CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get());
|
||||
|
||||
return VTable;
|
||||
}
|
||||
@ -933,8 +933,8 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
|
||||
const VTableLayout &VTLayout) {
|
||||
void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
|
||||
const VTableLayout &VTLayout) {
|
||||
if (!getCodeGenOpts().PrepareForLTO)
|
||||
return;
|
||||
|
||||
@ -973,10 +973,7 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
|
||||
return E1.second < E2.second;
|
||||
});
|
||||
|
||||
llvm::NamedMDNode *BitsetsMD =
|
||||
getModule().getOrInsertNamedMetadata("llvm.bitsets");
|
||||
for (auto BitsetEntry : BitsetEntries)
|
||||
CreateVTableBitSetEntry(BitsetsMD, VTable,
|
||||
PointerWidth * BitsetEntry.second,
|
||||
BitsetEntry.first);
|
||||
AddVTableTypeMetadata(VTable, PointerWidth * BitsetEntry.second,
|
||||
BitsetEntry.first);
|
||||
}
|
||||
|
@ -1413,15 +1413,15 @@ public:
|
||||
CFITypeCheckKind TCK, SourceLocation Loc);
|
||||
|
||||
/// EmitVTablePtrCheck - Emit a check that VTable is a valid virtual table for
|
||||
/// RD using llvm.bitset.test.
|
||||
/// RD using llvm.type.test.
|
||||
void EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable,
|
||||
CFITypeCheckKind TCK, SourceLocation Loc);
|
||||
|
||||
/// If whole-program virtual table optimization is enabled, emit an assumption
|
||||
/// that VTable is a member of the type's bitset. Or, if vptr CFI is enabled,
|
||||
/// emit a check that VTable is a member of the type's bitset.
|
||||
void EmitBitSetCodeForVCall(const CXXRecordDecl *RD, llvm::Value *VTable,
|
||||
SourceLocation Loc);
|
||||
/// that VTable is a member of RD's type identifier. Or, if vptr CFI is
|
||||
/// enabled, emit a check that VTable is a member of RD's type identifier.
|
||||
void EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
|
||||
llvm::Value *VTable, SourceLocation Loc);
|
||||
|
||||
/// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
|
||||
/// expr can be devirtualized.
|
||||
|
@ -787,8 +787,7 @@ void CodeGenModule::setFunctionDLLStorageClass(GlobalDecl GD, llvm::Function *F)
|
||||
F->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
|
||||
}
|
||||
|
||||
llvm::ConstantInt *
|
||||
CodeGenModule::CreateCfiIdForTypeMetadata(llvm::Metadata *MD) {
|
||||
llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) {
|
||||
llvm::MDString *MDS = dyn_cast<llvm::MDString>(MD);
|
||||
if (!MDS) return nullptr;
|
||||
|
||||
@ -989,8 +988,8 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV,
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenModule::CreateFunctionBitSetEntry(const FunctionDecl *FD,
|
||||
llvm::Function *F) {
|
||||
void CodeGenModule::CreateFunctionTypeMetadata(const FunctionDecl *FD,
|
||||
llvm::Function *F) {
|
||||
// Only if we are checking indirect calls.
|
||||
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
|
||||
return;
|
||||
@ -1011,25 +1010,13 @@ void CodeGenModule::CreateFunctionBitSetEntry(const FunctionDecl *FD,
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::NamedMDNode *BitsetsMD =
|
||||
getModule().getOrInsertNamedMetadata("llvm.bitsets");
|
||||
|
||||
llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
|
||||
llvm::Metadata *BitsetOps[] = {
|
||||
MD, llvm::ConstantAsMetadata::get(F),
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))};
|
||||
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
|
||||
F->addTypeMetadata(0, MD);
|
||||
|
||||
// Emit a hash-based bit set entry for cross-DSO calls.
|
||||
if (CodeGenOpts.SanitizeCfiCrossDso) {
|
||||
if (auto TypeId = CreateCfiIdForTypeMetadata(MD)) {
|
||||
llvm::Metadata *BitsetOps2[] = {
|
||||
llvm::ConstantAsMetadata::get(TypeId),
|
||||
llvm::ConstantAsMetadata::get(F),
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))};
|
||||
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2));
|
||||
}
|
||||
}
|
||||
if (CodeGenOpts.SanitizeCfiCrossDso)
|
||||
if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
|
||||
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
|
||||
}
|
||||
|
||||
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
|
||||
@ -1090,7 +1077,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
|
||||
if (MD->isVirtual())
|
||||
F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||
|
||||
CreateFunctionBitSetEntry(FD, F);
|
||||
CreateFunctionTypeMetadata(FD, F);
|
||||
}
|
||||
|
||||
void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {
|
||||
@ -4219,8 +4206,8 @@ llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) {
|
||||
return InternalId;
|
||||
}
|
||||
|
||||
/// Returns whether this module needs the "all-vtables" bitset.
|
||||
bool CodeGenModule::NeedAllVtablesBitSet() const {
|
||||
/// Returns whether this module needs the "all-vtables" type identifier.
|
||||
bool CodeGenModule::NeedAllVtablesTypeId() const {
|
||||
// Returns true if at least one of vtable-based CFI checkers is enabled and
|
||||
// is not in the trapping mode.
|
||||
return ((LangOpts.Sanitize.has(SanitizerKind::CFIVCall) &&
|
||||
@ -4233,38 +4220,21 @@ bool CodeGenModule::NeedAllVtablesBitSet() const {
|
||||
!CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFIUnrelatedCast)));
|
||||
}
|
||||
|
||||
void CodeGenModule::CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD,
|
||||
llvm::GlobalVariable *VTable,
|
||||
CharUnits Offset,
|
||||
const CXXRecordDecl *RD) {
|
||||
void CodeGenModule::AddVTableTypeMetadata(llvm::GlobalVariable *VTable,
|
||||
CharUnits Offset,
|
||||
const CXXRecordDecl *RD) {
|
||||
llvm::Metadata *MD =
|
||||
CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
|
||||
llvm::Metadata *BitsetOps[] = {
|
||||
MD, llvm::ConstantAsMetadata::get(VTable),
|
||||
llvm::ConstantAsMetadata::get(
|
||||
llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
|
||||
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
|
||||
VTable->addTypeMetadata(Offset.getQuantity(), MD);
|
||||
|
||||
if (CodeGenOpts.SanitizeCfiCrossDso) {
|
||||
if (auto TypeId = CreateCfiIdForTypeMetadata(MD)) {
|
||||
llvm::Metadata *BitsetOps2[] = {
|
||||
llvm::ConstantAsMetadata::get(TypeId),
|
||||
llvm::ConstantAsMetadata::get(VTable),
|
||||
llvm::ConstantAsMetadata::get(
|
||||
llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
|
||||
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2));
|
||||
}
|
||||
}
|
||||
if (CodeGenOpts.SanitizeCfiCrossDso)
|
||||
if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
|
||||
VTable->addTypeMetadata(Offset.getQuantity(),
|
||||
llvm::ConstantAsMetadata::get(CrossDsoTypeId));
|
||||
|
||||
if (NeedAllVtablesBitSet()) {
|
||||
if (NeedAllVtablesTypeId()) {
|
||||
llvm::Metadata *MD = llvm::MDString::get(getLLVMContext(), "all-vtables");
|
||||
llvm::Metadata *BitsetOps[] = {
|
||||
MD, llvm::ConstantAsMetadata::get(VTable),
|
||||
llvm::ConstantAsMetadata::get(
|
||||
llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
|
||||
// Avoid adding a node to BitsetsMD twice.
|
||||
if (!llvm::MDTuple::getIfExists(getLLVMContext(), BitsetOps))
|
||||
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
|
||||
VTable->addTypeMetadata(Offset.getQuantity(), MD);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1118,29 +1118,27 @@ public:
|
||||
/// optimization.
|
||||
bool HasHiddenLTOVisibility(const CXXRecordDecl *RD);
|
||||
|
||||
/// Emit bit set entries for the given vtable using the given layout if
|
||||
/// vptr CFI is enabled.
|
||||
void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
|
||||
const VTableLayout &VTLayout);
|
||||
/// Emit type metadata for the given vtable using the given layout.
|
||||
void EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
|
||||
const VTableLayout &VTLayout);
|
||||
|
||||
/// Generate a cross-DSO type identifier for type.
|
||||
llvm::ConstantInt *CreateCfiIdForTypeMetadata(llvm::Metadata *MD);
|
||||
/// Generate a cross-DSO type identifier for MD.
|
||||
llvm::ConstantInt *CreateCrossDsoCfiTypeId(llvm::Metadata *MD);
|
||||
|
||||
/// Create a metadata identifier for the given type. This may either be an
|
||||
/// MDString (for external identifiers) or a distinct unnamed MDNode (for
|
||||
/// internal identifiers).
|
||||
llvm::Metadata *CreateMetadataIdentifierForType(QualType T);
|
||||
|
||||
/// Create a bitset entry for the given function and add it to BitsetsMD.
|
||||
void CreateFunctionBitSetEntry(const FunctionDecl *FD, llvm::Function *F);
|
||||
/// Create and attach type metadata to the given function.
|
||||
void CreateFunctionTypeMetadata(const FunctionDecl *FD, llvm::Function *F);
|
||||
|
||||
/// Returns whether this module needs the "all-vtables" bitset.
|
||||
bool NeedAllVtablesBitSet() const;
|
||||
/// Returns whether this module needs the "all-vtables" type identifier.
|
||||
bool NeedAllVtablesTypeId() const;
|
||||
|
||||
/// Create a bitset entry for the given vtable and add it to BitsetsMD.
|
||||
void CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD,
|
||||
llvm::GlobalVariable *VTable, CharUnits Offset,
|
||||
const CXXRecordDecl *RD);
|
||||
/// Create and attach type metadata for the given vtable.
|
||||
void AddVTableTypeMetadata(llvm::GlobalVariable *VTable, CharUnits Offset,
|
||||
const CXXRecordDecl *RD);
|
||||
|
||||
/// \breif Get the declaration of std::terminate for the platform.
|
||||
llvm::Constant *getTerminateFn();
|
||||
|
@ -1490,7 +1490,7 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
|
||||
EmitFundamentalRTTIDescriptors();
|
||||
|
||||
if (!VTable->isDeclarationForLinker())
|
||||
CGM.EmitVTableBitSetEntries(VTable, VTLayout);
|
||||
CGM.EmitVTableTypeMetadata(VTable, VTLayout);
|
||||
}
|
||||
|
||||
bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
|
||||
@ -1595,7 +1595,7 @@ llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
|
||||
auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
|
||||
llvm::Value *VTable = CGF.GetVTablePtr(This, Ty, MethodDecl->getParent());
|
||||
|
||||
CGF.EmitBitSetCodeForVCall(MethodDecl->getParent(), VTable, Loc);
|
||||
CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc);
|
||||
|
||||
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
|
||||
llvm::Value *VFuncPtr =
|
||||
|
@ -254,8 +254,8 @@ public:
|
||||
CXXDtorType Type, bool ForVirtualBase,
|
||||
bool Delegating, Address This) override;
|
||||
|
||||
void emitVTableBitSetEntries(VPtrInfo *Info, const CXXRecordDecl *RD,
|
||||
llvm::GlobalVariable *VTable);
|
||||
void emitVTableTypeMetadata(VPtrInfo *Info, const CXXRecordDecl *RD,
|
||||
llvm::GlobalVariable *VTable);
|
||||
|
||||
void emitVTableDefinitions(CodeGenVTables &CGVT,
|
||||
const CXXRecordDecl *RD) override;
|
||||
@ -1502,15 +1502,12 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
|
||||
getFromDtorType(Type));
|
||||
}
|
||||
|
||||
void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
|
||||
const CXXRecordDecl *RD,
|
||||
llvm::GlobalVariable *VTable) {
|
||||
void MicrosoftCXXABI::emitVTableTypeMetadata(VPtrInfo *Info,
|
||||
const CXXRecordDecl *RD,
|
||||
llvm::GlobalVariable *VTable) {
|
||||
if (!CGM.getCodeGenOpts().PrepareForLTO)
|
||||
return;
|
||||
|
||||
llvm::NamedMDNode *BitsetsMD =
|
||||
CGM.getModule().getOrInsertNamedMetadata("llvm.bitsets");
|
||||
|
||||
// The location of the first virtual function pointer in the virtual table,
|
||||
// aka the "address point" on Itanium. This is at offset 0 if RTTI is
|
||||
// disabled, or sizeof(void*) if RTTI is enabled.
|
||||
@ -1521,13 +1518,13 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
|
||||
: CharUnits::Zero();
|
||||
|
||||
if (Info->PathToBaseWithVPtr.empty()) {
|
||||
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
|
||||
CGM.AddVTableTypeMetadata(VTable, AddressPoint, RD);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a bitset entry for the least derived base belonging to this vftable.
|
||||
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint,
|
||||
Info->PathToBaseWithVPtr.back());
|
||||
CGM.AddVTableTypeMetadata(VTable, AddressPoint,
|
||||
Info->PathToBaseWithVPtr.back());
|
||||
|
||||
// Add a bitset entry for each derived class that is laid out at the same
|
||||
// offset as the least derived base.
|
||||
@ -1545,12 +1542,12 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
|
||||
Offset = VBI->second.VBaseOffset;
|
||||
if (!Offset.isZero())
|
||||
return;
|
||||
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, DerivedRD);
|
||||
CGM.AddVTableTypeMetadata(VTable, AddressPoint, DerivedRD);
|
||||
}
|
||||
|
||||
// Finally do the same for the most derived class.
|
||||
if (Info->FullOffsetInMDC.isZero())
|
||||
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
|
||||
CGM.AddVTableTypeMetadata(VTable, AddressPoint, RD);
|
||||
}
|
||||
|
||||
void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
|
||||
@ -1578,7 +1575,7 @@ void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
|
||||
|
||||
VTable->setInitializer(Init);
|
||||
|
||||
emitVTableBitSetEntries(Info, RD, VTable);
|
||||
emitVTableTypeMetadata(Info, RD, VTable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1819,8 +1816,8 @@ llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
|
||||
MicrosoftVTableContext::MethodVFTableLocation ML =
|
||||
CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
|
||||
if (CGM.getCodeGenOpts().PrepareForLTO)
|
||||
CGF.EmitBitSetCodeForVCall(getClassAtVTableLocation(getContext(), GD, ML),
|
||||
VTable, Loc);
|
||||
CGF.EmitTypeMetadataCodeForVCall(
|
||||
getClassAtVTableLocation(getContext(), GD, ML), VTable, Loc);
|
||||
|
||||
llvm::Value *VFuncPtr =
|
||||
Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
|
||||
|
@ -23,7 +23,7 @@ void caller(void (*f)()) {
|
||||
// CHECK: %[[A:.*]] = bitcast i8* %[[DATA]] to { i8, { i8*, i32, i32 }, i8* }*
|
||||
// CHECK: %[[KINDPTR:.*]] = getelementptr {{.*}} %[[A]], i32 0, i32 0
|
||||
// CHECK: %[[KIND:.*]] = load i8, i8* %[[KINDPTR]], align 4
|
||||
// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata !"all-vtables")
|
||||
// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.type.test(i8* %[[ADDR]], metadata !"all-vtables")
|
||||
// CHECK: %[[VTVALID:.*]] = zext i1 %[[VTVALID0]] to i64
|
||||
// CHECK: %[[NOT_0:.*]] = icmp ne i8 %[[KIND]], 0
|
||||
// CHECK: br i1 %[[NOT_0]], label %[[CONT1:.*]], label %[[HANDLE0:.*]], !prof
|
||||
|
@ -23,7 +23,7 @@ void caller(void (*f)()) {
|
||||
// CHECK: %[[A:.*]] = bitcast i8* %[[DATA]] to { i8, { i8*, i32, i32 }, i8* }*
|
||||
// CHECK: %[[KINDPTR:.*]] = getelementptr {{.*}} %[[A]], i32 0, i32 0
|
||||
// CHECK: %[[KIND:.*]] = load i8, i8* %[[KINDPTR]], align 4
|
||||
// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata !"all-vtables")
|
||||
// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.type.test(i8* %[[ADDR]], metadata !"all-vtables")
|
||||
// CHECK: %[[VTVALID:.*]] = zext i1 %[[VTVALID0]] to i64
|
||||
// CHECK: %[[NOT_0:.*]] = icmp ne i8 %[[KIND]], 0
|
||||
// CHECK: br i1 %[[NOT_0]], label %[[CONT1:.*]], label %[[HANDLE0:.*]], !prof
|
||||
|
@ -26,11 +26,30 @@
|
||||
// RUN: --check-prefix=MS --check-prefix=MS-TRAP \
|
||||
// RUN: %s
|
||||
|
||||
// CHECK-DIAG: @[[SRC:.*]] = private unnamed_addr constant {{.*}}cfi-icall-cross-dso.c\00
|
||||
// CHECK-DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [{{.*}} x i8] } { i16 -1, i16 0, [{{.*}} x i8] c"'void ()'\00"
|
||||
// CHECK-DIAG: @[[DATA:.*]] = private unnamed_addr global {{.*}}@[[SRC]]{{.*}}@[[TYPE]]
|
||||
|
||||
|
||||
// ITANIUM: call i1 @llvm.type.test(i8* %{{.*}}, metadata !"_ZTSFvE"), !nosanitize
|
||||
// ITANIUM-DIAG: call void @__cfi_slowpath_diag(i64 6588678392271548388, i8* %{{.*}}, {{.*}}@[[DATA]]{{.*}}) {{.*}}, !nosanitize
|
||||
// ITANIUM-TRAP: call void @__cfi_slowpath(i64 6588678392271548388, i8* %{{.*}}) {{.*}}, !nosanitize
|
||||
|
||||
// MS: call i1 @llvm.type.test(i8* %{{.*}}, metadata !"?6AX@Z"), !nosanitize
|
||||
// MS-DIAG: call void @__cfi_slowpath_diag(i64 4195979634929632483, i8* %{{.*}}, {{.*}}@[[DATA]]{{.*}}) {{.*}}, !nosanitize
|
||||
// MS-TRAP: call void @__cfi_slowpath(i64 4195979634929632483, i8* %{{.*}}) {{.*}}, !nosanitize
|
||||
|
||||
void caller(void (*f)()) {
|
||||
f();
|
||||
}
|
||||
|
||||
// Check that we emit both string and hash based type entries for static void g(),
|
||||
// and don't emit them for the declaration of h().
|
||||
|
||||
// CHECK: define internal void @g({{.*}} !type [[TVOID:![0-9]+]] !type [[TVOID_ID:![0-9]+]]
|
||||
static void g(void) {}
|
||||
|
||||
// CHECK: declare void @h({{[^!]*$}}
|
||||
void h(void);
|
||||
|
||||
typedef void (*Fn)(void);
|
||||
@ -41,41 +60,22 @@ Fn h1() {
|
||||
return &h;
|
||||
}
|
||||
|
||||
// CHECK: define void @bar({{.*}} !type [[TNOPROTO:![0-9]+]] !type [[TNOPROTO_ID:![0-9]+]]
|
||||
// ITANIUM: define available_externally void @foo({{[^!]*$}}
|
||||
// MS: define linkonce_odr void @foo({{.*}} !type [[TNOPROTO]] !type [[TNOPROTO_ID]]
|
||||
inline void foo() {}
|
||||
void bar() { foo(); }
|
||||
|
||||
// CHECK-DIAG: @[[SRC:.*]] = private unnamed_addr constant {{.*}}cfi-icall-cross-dso.c\00
|
||||
// CHECK-DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [{{.*}} x i8] } { i16 -1, i16 0, [{{.*}} x i8] c"'void ()'\00"
|
||||
// CHECK-DIAG: @[[DATA:.*]] = private unnamed_addr global {{.*}}@[[SRC]]{{.*}}@[[TYPE]]
|
||||
|
||||
|
||||
// ITANIUM: call i1 @llvm.bitset.test(i8* %{{.*}}, metadata !"_ZTSFvE"), !nosanitize
|
||||
// ITANIUM-DIAG: call void @__cfi_slowpath_diag(i64 6588678392271548388, i8* %{{.*}}, {{.*}}@[[DATA]]{{.*}}) {{.*}}, !nosanitize
|
||||
// ITANIUM-TRAP: call void @__cfi_slowpath(i64 6588678392271548388, i8* %{{.*}}) {{.*}}, !nosanitize
|
||||
|
||||
// MS: call i1 @llvm.bitset.test(i8* %{{.*}}, metadata !"?6AX@Z"), !nosanitize
|
||||
// MS-DIAG: call void @__cfi_slowpath_diag(i64 4195979634929632483, i8* %{{.*}}, {{.*}}@[[DATA]]{{.*}}) {{.*}}, !nosanitize
|
||||
// MS-TRAP: call void @__cfi_slowpath(i64 4195979634929632483, i8* %{{.*}}) {{.*}}, !nosanitize
|
||||
|
||||
// ITANIUM: define available_externally void @foo()
|
||||
// MS: define linkonce_odr void @foo()
|
||||
|
||||
// Check that we emit both string and hash based bit set entries for static void g(),
|
||||
// and don't emit them for the declaration of h().
|
||||
|
||||
// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
|
||||
// CHECK: !{!"{{.*}}", void ()* @g, i64 0}
|
||||
// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
|
||||
// CHECK: !{i64 {{.*}}, void ()* @g, i64 0}
|
||||
// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
|
||||
|
||||
// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
|
||||
// ITANIUM: !{!"_ZTSFvE", void ()* @bar, i64 0}
|
||||
// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
|
||||
// ITANIUM: !{i64 6588678392271548388, void ()* @bar, i64 0}
|
||||
// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
|
||||
|
||||
// MS: !{!"?6AX@Z", void ()* @foo, i64 0}
|
||||
// MS: !{i64 4195979634929632483, void ()* @foo, i64 0}
|
||||
|
||||
// CHECK: !{i32 4, !"Cross-DSO CFI", i32 1}
|
||||
|
||||
// Check that the type entries are correct.
|
||||
|
||||
// ITANIUM: [[TVOID]] = !{i64 0, !"_ZTSFvvE"}
|
||||
// ITANIUM: [[TVOID_ID]] = !{i64 0, i64 9080559750644022485}
|
||||
// ITANIUM: [[TNOPROTO]] = !{i64 0, !"_ZTSFvE"}
|
||||
// ITANIUM: [[TNOPROTO_ID]] = !{i64 0, i64 6588678392271548388}
|
||||
|
||||
// MS: [[TVOID]] = !{i64 0, !"?6AXXZ"}
|
||||
// MS: [[TVOID_ID]] = !{i64 0, i64 5113650790573562461}
|
||||
// MS: [[TNOPROTO]] = !{i64 0, !"?6AX@Z"}
|
||||
// MS: [[TNOPROTO_ID]] = !{i64 0, i64 4195979634929632483}
|
||||
|
@ -1,20 +1,24 @@
|
||||
// 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
|
||||
// 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 appropriate identifiers to unprototyped functions.
|
||||
|
||||
// CHECK: define void @f({{.*}} !type [[TVOID:![0-9]+]]
|
||||
void f() {
|
||||
}
|
||||
|
||||
void xf();
|
||||
|
||||
// CHECK: define void @g({{.*}} !type [[TINT:![0-9]+]]
|
||||
void g(int b) {
|
||||
void (*fp)() = b ? f : xf;
|
||||
// ITANIUM: call i1 @llvm.bitset.test(i8* {{.*}}, metadata !"_ZTSFvE")
|
||||
// ITANIUM: call i1 @llvm.type.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}
|
||||
// CHECK: declare !type [[TVOID:![0-9]+]] void @xf({{.*}}
|
||||
|
||||
// ITANIUM-DAG: [[TVOID]] = !{i64 0, !"_ZTSFvE"}
|
||||
// ITANIUM-DAG: [[TINT]] = !{i64 0, !"_ZTSFviE"}
|
||||
// MS-DAG: [[TVOID]] = !{i64 0, !"?6AX@Z"}
|
||||
// MS-DAG: [[TINT]] = !{i64 0, !"?6AXH@Z"}
|
||||
|
@ -1,211 +0,0 @@
|
||||
// Tests for the cfi-vcall feature:
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=MS --check-prefix=NDIAG %s
|
||||
|
||||
// Tests for the whole-program-vtables feature:
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM %s
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS %s
|
||||
|
||||
// MS: @[[VTA:[0-9]*]] {{.*}} comdat($"\01??_7A@@6B@")
|
||||
// MS: @[[VTB:[0-9]*]] {{.*}} comdat($"\01??_7B@@6B0@@")
|
||||
// MS: @[[VTAinB:[0-9]*]] {{.*}} comdat($"\01??_7B@@6BA@@@")
|
||||
// MS: @[[VTAinC:[0-9]*]] {{.*}} comdat($"\01??_7C@@6B@")
|
||||
// MS: @[[VTBinD:[0-9]*]] {{.*}} comdat($"\01??_7D@?A@@6BB@@@")
|
||||
// MS: @[[VTAinBinD:[0-9]*]] {{.*}} comdat($"\01??_7D@?A@@6BA@@@")
|
||||
// MS: @[[VTFA:[0-9]*]] {{.*}} comdat($"\01??_7FA@?1??foo@@YAXXZ@6B@")
|
||||
|
||||
struct A {
|
||||
A();
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
struct B : virtual A {
|
||||
B();
|
||||
virtual void g();
|
||||
virtual void h();
|
||||
};
|
||||
|
||||
struct C : virtual A {
|
||||
C();
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
struct D : B, C {
|
||||
D();
|
||||
virtual void f();
|
||||
virtual void h();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
A::A() {}
|
||||
B::B() {}
|
||||
C::C() {}
|
||||
D::D() {}
|
||||
|
||||
void A::f() {
|
||||
}
|
||||
|
||||
void B::g() {
|
||||
}
|
||||
|
||||
void D::f() {
|
||||
}
|
||||
|
||||
void D::h() {
|
||||
}
|
||||
|
||||
// DIAG: @[[SRC:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}bitsets.cpp\00", align 1
|
||||
// DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [4 x i8] } { i16 -1, i16 0, [4 x i8] c"'A'\00" }
|
||||
// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }* } { i8 0, { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 [[@LINE+24]], i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]] }
|
||||
|
||||
// ITANIUM: define hidden void @_Z2afP1A
|
||||
// MS: define void @"\01?af@@YAXPEAUA@@@Z"
|
||||
void af(A *a) {
|
||||
// ITANIUM: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A")
|
||||
// MS: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"?AUA@@")
|
||||
// DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT]], metadata !"all-vtables")
|
||||
// VTABLE-OPT: call void @llvm.assume(i1 [[P]])
|
||||
// CFI-NEXT: br i1 [[P]], label %[[CONTBB:[^ ,]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
// CFI-NEXT: {{^$}}
|
||||
|
||||
// CFI: [[TRAPBB]]
|
||||
// NDIAG-NEXT: call void @llvm.trap()
|
||||
// NDIAG-NEXT: unreachable
|
||||
// DIAG-NEXT: [[VTINT:%[^ ]*]] = ptrtoint i8* [[VT]] to i64
|
||||
// DIAG-NEXT: [[VTVALID:%[^ ]*]] = zext i1 [[VTVALID0]] to i64
|
||||
// DIAG-ABORT-NEXT: call void @__ubsan_handle_cfi_check_fail_abort(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
|
||||
// DIAG-ABORT-NEXT: unreachable
|
||||
// DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_check_fail(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
|
||||
// DIAG-RECOVER-NEXT: br label %[[CONTBB]]
|
||||
|
||||
// CFI: [[CONTBB]]
|
||||
// CFI: call void %
|
||||
a->f();
|
||||
}
|
||||
|
||||
// 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 ![[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 !"_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 ![[DTYPE]])
|
||||
// MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
|
||||
d->h();
|
||||
}
|
||||
|
||||
// ITANIUM: define internal void @_Z3df2PN12_GLOBAL__N_11DE
|
||||
// MS: define internal void @"\01?df2@@YAXPEAUD@?A@@@Z"
|
||||
__attribute__((no_sanitize("cfi")))
|
||||
void df2(D *d) {
|
||||
// CFI-NOT: call i1 @llvm.bitset.test
|
||||
d->f();
|
||||
}
|
||||
|
||||
// ITANIUM: define internal void @_Z3df3PN12_GLOBAL__N_11DE
|
||||
// MS: define internal void @"\01?df3@@YAXPEAUD@?A@@@Z"
|
||||
__attribute__((no_sanitize("address"))) __attribute__((no_sanitize("cfi-vcall")))
|
||||
void df3(D *d) {
|
||||
// CFI-NOT: call i1 @llvm.bitset.test
|
||||
d->f();
|
||||
}
|
||||
|
||||
D d;
|
||||
|
||||
void foo() {
|
||||
df1(&d);
|
||||
dg1(&d);
|
||||
dh1(&d);
|
||||
df2(&d);
|
||||
df3(&d);
|
||||
|
||||
struct FA : A {
|
||||
void f() {}
|
||||
} fa;
|
||||
af(&fa);
|
||||
}
|
||||
|
||||
namespace test2 {
|
||||
|
||||
struct A {
|
||||
virtual void m_fn1();
|
||||
};
|
||||
struct B {
|
||||
virtual void m_fn2();
|
||||
};
|
||||
struct C : B, A {};
|
||||
struct D : C {
|
||||
void m_fn1();
|
||||
};
|
||||
|
||||
// ITANIUM: define hidden void @_ZN5test21fEPNS_1DE
|
||||
// MS: define void @"\01?f@test2@@YAXPEAUD@1@@Z"
|
||||
void f(D *d) {
|
||||
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
|
||||
// MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"?AUA@test2@@")
|
||||
d->m_fn1();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check for the expected number of elements (15 or 23 respectively).
|
||||
// MS-NDIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){9}]]}
|
||||
// MS-DIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){15}]]}
|
||||
// ITANIUM-NDIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){14}]]}
|
||||
// ITANIUM-DIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){23}]]}
|
||||
|
||||
// ITANIUM-DAG: !{!"_ZTS1A", [3 x i8*]* @_ZTV1A, i64 16}
|
||||
// ITANIUM-DIAG-DAG: !{!"all-vtables", [3 x i8*]* @_ZTV1A, i64 16}
|
||||
// ITANIUM-DAG: !{!"_ZTS1A", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
|
||||
// ITANIUM-DIAG-DAG: !{!"all-vtables", [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-DIAG-DAG: !{!"all-vtables", [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-DIAG-DAG: !{!"all-vtables", [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-DIAG-DAG: !{!"all-vtables", [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-DIAG-DAG: !{!"all-vtables", [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-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTA]], i64 8}
|
||||
// MS-DAG: !{!"?AUB@@", [3 x i8*]* @[[VTB]], i64 8}
|
||||
// MS-DIAG-DAG: !{!"all-vtables", [3 x i8*]* @[[VTB]], i64 8}
|
||||
// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinB]], i64 8}
|
||||
// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinB]], i64 8}
|
||||
// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinC]], i64 8}
|
||||
// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinC]], i64 8}
|
||||
// MS-DAG: !{!"?AUB@@", [3 x i8*]* @[[VTBinD]], i64 8}
|
||||
// MS-DIAG-DAG: !{!"all-vtables", [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-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinBinD]], i64 8}
|
||||
// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTFA]], i64 8}
|
||||
// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTFA]], i64 8}
|
||||
// MS-DAG: !{!{{[0-9]+}}, [2 x i8*]* @[[VTFA]], i64 8}
|
@ -15,15 +15,15 @@ struct S2 {
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}}s1f
|
||||
// NOBL: llvm.bitset.test
|
||||
// NOSTD: llvm.bitset.test
|
||||
// NOBL: llvm.type.test
|
||||
// NOSTD: llvm.type.test
|
||||
void s1f(S1 *s1) {
|
||||
s1->f();
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}}s2f
|
||||
// NOBL: llvm.bitset.test
|
||||
// NOSTD-NOT: llvm.bitset.test
|
||||
// NOBL: llvm.type.test
|
||||
// NOSTD-NOT: llvm.type.test
|
||||
void s2f(std::S2 *s2) {
|
||||
s2->f();
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ struct C : A {};
|
||||
|
||||
// CHECK-DCAST-LABEL: define hidden void @_Z3abpP1A
|
||||
void abp(A *a) {
|
||||
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-DCAST: [[TRAPBB]]
|
||||
@ -33,7 +33,7 @@ void abp(A *a) {
|
||||
|
||||
// CHECK-DCAST-LABEL: define hidden void @_Z3abrR1A
|
||||
void abr(A &a) {
|
||||
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-DCAST: [[TRAPBB]]
|
||||
@ -47,7 +47,7 @@ void abr(A &a) {
|
||||
|
||||
// CHECK-DCAST-LABEL: define hidden void @_Z4abrrO1A
|
||||
void abrr(A &&a) {
|
||||
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-DCAST: [[TRAPBB]]
|
||||
@ -61,7 +61,7 @@ void abrr(A &&a) {
|
||||
|
||||
// CHECK-UCAST-LABEL: define hidden void @_Z3vbpPv
|
||||
void vbp(void *p) {
|
||||
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-UCAST: [[TRAPBB]]
|
||||
@ -75,7 +75,7 @@ void vbp(void *p) {
|
||||
|
||||
// CHECK-UCAST-LABEL: define hidden void @_Z3vbrRc
|
||||
void vbr(char &r) {
|
||||
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-UCAST: [[TRAPBB]]
|
||||
@ -89,7 +89,7 @@ void vbr(char &r) {
|
||||
|
||||
// CHECK-UCAST-LABEL: define hidden void @_Z4vbrrOc
|
||||
void vbrr(char &&r) {
|
||||
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-UCAST: [[TRAPBB]]
|
||||
@ -104,31 +104,31 @@ void vbrr(char &&r) {
|
||||
// CHECK-UCAST-LABEL: define hidden void @_Z3vcpPv
|
||||
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z3vcpPv
|
||||
void vcp(void *p) {
|
||||
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
|
||||
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
|
||||
// CHECK-UCAST: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
|
||||
// CHECK-UCAST-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
|
||||
(void)static_cast<C*>(p);
|
||||
}
|
||||
|
||||
// CHECK-UCAST-LABEL: define hidden void @_Z3bcpP1B
|
||||
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z3bcpP1B
|
||||
void bcp(B *p) {
|
||||
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
|
||||
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
|
||||
// CHECK-UCAST: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
|
||||
// CHECK-UCAST-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
|
||||
(void)(C *)p;
|
||||
}
|
||||
|
||||
// CHECK-UCAST-LABEL: define hidden void @_Z8bcp_callP1B
|
||||
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z8bcp_callP1B
|
||||
void bcp_call(B *p) {
|
||||
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
|
||||
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
|
||||
// CHECK-UCAST: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
|
||||
// CHECK-UCAST-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
|
||||
((C *)p)->f();
|
||||
}
|
||||
|
||||
// CHECK-UCAST-LABEL: define hidden i32 @_Z6a_callP1A
|
||||
// CHECK-UCAST-STRICT-LABEL: define hidden i32 @_Z6a_callP1A
|
||||
int a_call(A *a) {
|
||||
// CHECK-UCAST-NOT: @llvm.bitset.test
|
||||
// CHECK-UCAST-STRICT-NOT: @llvm.bitset.test
|
||||
// CHECK-UCAST-NOT: @llvm.type.test
|
||||
// CHECK-UCAST-STRICT-NOT: @llvm.type.test
|
||||
return a->i();
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ void g() {
|
||||
|
||||
// CHECK: %[[VT:.*]] = load void (%struct.A*)**, void (%struct.A*)***
|
||||
// CHECK: %[[VT2:.*]] = bitcast {{.*}}%[[VT]] to i8*, !nosanitize
|
||||
// ITANIUM: %[[TEST:.*]] = call i1 @llvm.bitset.test(i8* %[[VT2]], metadata !"_ZTS1A"), !nosanitize
|
||||
// MS: %[[TEST:.*]] = call i1 @llvm.bitset.test(i8* %[[VT2]], metadata !"?AUA@@"), !nosanitize
|
||||
// ITANIUM: %[[TEST:.*]] = call i1 @llvm.type.test(i8* %[[VT2]], metadata !"_ZTS1A"), !nosanitize
|
||||
// MS: %[[TEST:.*]] = call i1 @llvm.type.test(i8* %[[VT2]], metadata !"?AUA@@"), !nosanitize
|
||||
// CHECK: br i1 %[[TEST]], label %[[CONT:.*]], label %[[SLOW:.*]], {{.*}} !nosanitize
|
||||
// CHECK: [[SLOW]]
|
||||
// ITANIUM: call void @__cfi_slowpath_diag(i64 7004155349499253778, i8* %[[VT2]], {{.*}}) {{.*}} !nosanitize
|
||||
|
@ -15,9 +15,12 @@ void f(S *s) {
|
||||
|
||||
void g() {
|
||||
void (*fp)(S *) = f;
|
||||
// CHECK: call i1 @llvm.bitset.test(i8* {{.*}}, metadata ![[VOIDS:[0-9]+]])
|
||||
// CHECK: call i1 @llvm.type.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}
|
||||
// ITANIUM: define internal void @_ZN12_GLOBAL__N_11fEPNS_1SE({{.*}} !type [[TS:![0-9]+]]
|
||||
// MS: define internal void @"\01?f@?A@@YAXPEAUS@?A@@@Z"({{.*}} !type [[TS:![0-9]+]]
|
||||
|
||||
// CHECK: [[VOIDS]] = distinct !{}
|
||||
// CHECK: [[TS]] = !{i64 0, [[VOIDS]]}
|
||||
|
@ -8,5 +8,5 @@ struct A {
|
||||
|
||||
A::A() {}
|
||||
|
||||
// RTTI: !{!"?AUA@@", [2 x i8*]* {{.*}}, i64 8}
|
||||
// NO-RTTI: !{!"?AUA@@", [1 x i8*]* {{.*}}, i64 0}
|
||||
// RTTI: !{i64 8, !"?AUA@@"}
|
||||
// NO-RTTI: !{i64 0, !"?AUA@@"}
|
||||
|
@ -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 !"_ZTS1B")
|
||||
// CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// CHECK-STRICT: call i1 @llvm.type.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 !"_ZTS1A")
|
||||
// CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
|
||||
// CHECK: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
|
||||
// CHECK-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
|
||||
c->g();
|
||||
}
|
||||
|
@ -67,41 +67,41 @@ struct C11 {
|
||||
|
||||
void f(C1 *c1, C2 *c2, C3 *c3, C4 *c4, C5 *c5, C6 *c6, std::C7 *c7,
|
||||
std::C7::C8 *c8, stdext::C9 *c9, other::C10 *c10) {
|
||||
// ITANIUM: bitset.test{{.*}}!"_ZTS2C1"
|
||||
// MS: bitset.test{{.*}}!"?AUC1@@"
|
||||
// ITANIUM: type.test{{.*}}!"_ZTS2C1"
|
||||
// MS: type.test{{.*}}!"?AUC1@@"
|
||||
c1->f();
|
||||
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C2"
|
||||
// MS: bitset.test{{.*}}!"?AUC2@@"
|
||||
// ITANIUM-NOT: type.test{{.*}}!"_ZTS2C2"
|
||||
// MS: type.test{{.*}}!"?AUC2@@"
|
||||
c2->f();
|
||||
// ITANIUM: bitset.test{{.*}}!"_ZTS2C3"
|
||||
// MS-NOT: bitset.test{{.*}}!"?AUC3@@"
|
||||
// ITANIUM: type.test{{.*}}!"_ZTS2C3"
|
||||
// MS-NOT: type.test{{.*}}!"?AUC3@@"
|
||||
c3->f();
|
||||
// ITANIUM: bitset.test{{.*}}!"_ZTS2C4"
|
||||
// MS-NOT: bitset.test{{.*}}!"?AUC4@@"
|
||||
// ITANIUM: type.test{{.*}}!"_ZTS2C4"
|
||||
// MS-NOT: type.test{{.*}}!"?AUC4@@"
|
||||
c4->f();
|
||||
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C5"
|
||||
// MS-NOT: bitset.test{{.*}}!"?AUC5@@"
|
||||
// ITANIUM-NOT: type.test{{.*}}!"_ZTS2C5"
|
||||
// MS-NOT: type.test{{.*}}!"?AUC5@@"
|
||||
c5->f();
|
||||
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C6"
|
||||
// MS-NOT: bitset.test{{.*}}!"?AUC6@@"
|
||||
// ITANIUM-NOT: type.test{{.*}}!"_ZTS2C6"
|
||||
// MS-NOT: type.test{{.*}}!"?AUC6@@"
|
||||
c6->f();
|
||||
// ITANIUM: bitset.test{{.*}}!"_ZTSSt2C7"
|
||||
// MS-STD: bitset.test{{.*}}!"?AUC7@std@@"
|
||||
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC7@std@@"
|
||||
// ITANIUM: type.test{{.*}}!"_ZTSSt2C7"
|
||||
// MS-STD: type.test{{.*}}!"?AUC7@std@@"
|
||||
// MS-NOSTD-NOT: type.test{{.*}}!"?AUC7@std@@"
|
||||
c7->f();
|
||||
// ITANIUM: bitset.test{{.*}}!"_ZTSNSt2C72C8E"
|
||||
// MS-STD: bitset.test{{.*}}!"?AUC8@C7@std@@"
|
||||
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC8@C7@std@@"
|
||||
// ITANIUM: type.test{{.*}}!"_ZTSNSt2C72C8E"
|
||||
// MS-STD: type.test{{.*}}!"?AUC8@C7@std@@"
|
||||
// MS-NOSTD-NOT: type.test{{.*}}!"?AUC8@C7@std@@"
|
||||
c8->f();
|
||||
// ITANIUM: bitset.test{{.*}}!"_ZTSN6stdext2C9E"
|
||||
// MS-STD: bitset.test{{.*}}!"?AUC9@stdext@@"
|
||||
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC9@stdext@@"
|
||||
// ITANIUM: type.test{{.*}}!"_ZTSN6stdext2C9E"
|
||||
// MS-STD: type.test{{.*}}!"?AUC9@stdext@@"
|
||||
// MS-NOSTD-NOT: type.test{{.*}}!"?AUC9@stdext@@"
|
||||
c9->f();
|
||||
// ITANIUM: bitset.test{{.*}}!"_ZTSN5other3C10E"
|
||||
// MS: bitset.test{{.*}}!"?AUC10@other@@"
|
||||
// ITANIUM: type.test{{.*}}!"_ZTSN5other3C10E"
|
||||
// MS: type.test{{.*}}!"?AUC10@other@@"
|
||||
c10->f();
|
||||
// ITANIUM: bitset.test{{.*}}!{{[0-9]}}
|
||||
// MS: bitset.test{{.*}}!{{[0-9]}}
|
||||
// ITANIUM: type.test{{.*}}!{{[0-9]}}
|
||||
// MS: type.test{{.*}}!{{[0-9]}}
|
||||
C11 *c11;
|
||||
c11->f();
|
||||
}
|
226
clang/test/CodeGenCXX/type-metadata.cpp
Normal file
226
clang/test/CodeGenCXX/type-metadata.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
// Tests for the cfi-vcall feature:
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=MS --check-prefix=NDIAG %s
|
||||
|
||||
// Tests for the whole-program-vtables feature:
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM %s
|
||||
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS %s
|
||||
|
||||
// ITANIUM: @_ZTV1A = {{[^!]*}}, !type [[A16:![0-9]+]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL16:![0-9]+]]
|
||||
|
||||
// ITANIUM: @_ZTV1B = {{[^!]*}}, !type [[A32:![0-9]+]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32:![0-9]+]]
|
||||
// ITANIUM-SAME: !type [[B32:![0-9]+]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
|
||||
// ITANIUM: @_ZTV1C = {{[^!]*}}, !type [[A32]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
// ITANIUM-SAME: !type [[C32:![0-9]+]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
|
||||
// DIAG: @[[SRC:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}type-metadata.cpp\00", align 1
|
||||
// DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [4 x i8] } { i16 -1, i16 0, [4 x i8] c"'A'\00" }
|
||||
// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }* } { i8 0, { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 123, i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]] }
|
||||
|
||||
// ITANIUM: @_ZTVN12_GLOBAL__N_11DE = {{[^!]*}}, !type [[A32]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
// ITANIUM-SAME: !type [[B32]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
// ITANIUM-SAME: !type [[C88:![0-9]+]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL88:![0-9]+]]
|
||||
// ITANIUM-SAME: !type [[D32:![0-9]+]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
|
||||
// ITANIUM: @_ZTCN12_GLOBAL__N_11DE0_1B = {{[^!]*}}, !type [[A32]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
// ITANIUM-SAME: !type [[B32]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
|
||||
// ITANIUM: @_ZTCN12_GLOBAL__N_11DE8_1C = {{[^!]*}}, !type [[A64:![0-9]+]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL64:![0-9]+]]
|
||||
// ITANIUM-SAME: !type [[C32]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL32]]
|
||||
|
||||
// ITANIUM: @_ZTVZ3foovE2FA = {{[^!]*}}, !type [[A16]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL16]]
|
||||
// ITANIUM-SAME: !type [[FA16:![0-9]+]]
|
||||
// ITANIUM-DIAG-SAME: !type [[ALL16]]
|
||||
|
||||
// MS: comdat($"\01??_7A@@6B@"), !type [[A8:![0-9]+]]
|
||||
// MS: comdat($"\01??_7B@@6B0@@"), !type [[B8:![0-9]+]]
|
||||
// MS: comdat($"\01??_7B@@6BA@@@"), !type [[A8]]
|
||||
// MS: comdat($"\01??_7C@@6B@"), !type [[A8]]
|
||||
// MS: comdat($"\01??_7D@?A@@6BB@@@"), !type [[B8]], !type [[D8:![0-9]+]]
|
||||
// MS: comdat($"\01??_7D@?A@@6BA@@@"), !type [[A8]]
|
||||
// MS: comdat($"\01??_7FA@?1??foo@@YAXXZ@6B@"), !type [[A8]], !type [[FA8:![0-9]+]]
|
||||
|
||||
struct A {
|
||||
A();
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
struct B : virtual A {
|
||||
B();
|
||||
virtual void g();
|
||||
virtual void h();
|
||||
};
|
||||
|
||||
struct C : virtual A {
|
||||
C();
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
struct D : B, C {
|
||||
D();
|
||||
virtual void f();
|
||||
virtual void h();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
A::A() {}
|
||||
B::B() {}
|
||||
C::C() {}
|
||||
D::D() {}
|
||||
|
||||
void A::f() {
|
||||
}
|
||||
|
||||
void B::g() {
|
||||
}
|
||||
|
||||
void D::f() {
|
||||
}
|
||||
|
||||
void D::h() {
|
||||
}
|
||||
|
||||
// ITANIUM: define hidden void @_Z2afP1A
|
||||
// MS: define void @"\01?af@@YAXPEAUA@@@Z"
|
||||
void af(A *a) {
|
||||
// ITANIUM: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A")
|
||||
// MS: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT:%[^ ]*]], metadata !"?AUA@@")
|
||||
// DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT]], metadata !"all-vtables")
|
||||
// VTABLE-OPT: call void @llvm.assume(i1 [[P]])
|
||||
// CFI-NEXT: br i1 [[P]], label %[[CONTBB:[^ ,]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
// CFI-NEXT: {{^$}}
|
||||
|
||||
// CFI: [[TRAPBB]]
|
||||
// NDIAG-NEXT: call void @llvm.trap()
|
||||
// NDIAG-NEXT: unreachable
|
||||
// DIAG-NEXT: [[VTINT:%[^ ]*]] = ptrtoint i8* [[VT]] to i64
|
||||
// DIAG-NEXT: [[VTVALID:%[^ ]*]] = zext i1 [[VTVALID0]] to i64
|
||||
// DIAG-ABORT-NEXT: call void @__ubsan_handle_cfi_check_fail_abort(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
|
||||
// DIAG-ABORT-NEXT: unreachable
|
||||
// DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_check_fail(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
|
||||
// DIAG-RECOVER-NEXT: br label %[[CONTBB]]
|
||||
|
||||
// CFI: [[CONTBB]]
|
||||
// CFI: call void %
|
||||
#line 123
|
||||
a->f();
|
||||
}
|
||||
|
||||
// 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.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
|
||||
// MS: {{%[^ ]*}} = call i1 @llvm.type.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.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
|
||||
// MS: {{%[^ ]*}} = call i1 @llvm.type.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.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE]])
|
||||
// MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
|
||||
d->h();
|
||||
}
|
||||
|
||||
// ITANIUM: define internal void @_Z3df2PN12_GLOBAL__N_11DE
|
||||
// MS: define internal void @"\01?df2@@YAXPEAUD@?A@@@Z"
|
||||
__attribute__((no_sanitize("cfi")))
|
||||
void df2(D *d) {
|
||||
// CFI-NOT: call i1 @llvm.type.test
|
||||
d->f();
|
||||
}
|
||||
|
||||
// ITANIUM: define internal void @_Z3df3PN12_GLOBAL__N_11DE
|
||||
// MS: define internal void @"\01?df3@@YAXPEAUD@?A@@@Z"
|
||||
__attribute__((no_sanitize("address"))) __attribute__((no_sanitize("cfi-vcall")))
|
||||
void df3(D *d) {
|
||||
// CFI-NOT: call i1 @llvm.type.test
|
||||
d->f();
|
||||
}
|
||||
|
||||
D d;
|
||||
|
||||
void foo() {
|
||||
df1(&d);
|
||||
dg1(&d);
|
||||
dh1(&d);
|
||||
df2(&d);
|
||||
df3(&d);
|
||||
|
||||
struct FA : A {
|
||||
void f() {}
|
||||
} fa;
|
||||
af(&fa);
|
||||
}
|
||||
|
||||
namespace test2 {
|
||||
|
||||
struct A {
|
||||
virtual void m_fn1();
|
||||
};
|
||||
struct B {
|
||||
virtual void m_fn2();
|
||||
};
|
||||
struct C : B, A {};
|
||||
struct D : C {
|
||||
void m_fn1();
|
||||
};
|
||||
|
||||
// ITANIUM: define hidden void @_ZN5test21fEPNS_1DE
|
||||
// MS: define void @"\01?f@test2@@YAXPEAUD@1@@Z"
|
||||
void f(D *d) {
|
||||
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
|
||||
// MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"?AUA@test2@@")
|
||||
d->m_fn1();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ITANIUM: [[A16]] = !{i64 16, !"_ZTS1A"}
|
||||
// ITANIUM-DIAG: [[ALL16]] = !{i64 16, !"all-vtables"}
|
||||
// ITANIUM: [[A32]] = !{i64 32, !"_ZTS1A"}
|
||||
// ITANIUM-DIAG: [[ALL32]] = !{i64 32, !"all-vtables"}
|
||||
// ITANIUM: [[B32]] = !{i64 32, !"_ZTS1B"}
|
||||
// ITANIUM: [[C32]] = !{i64 32, !"_ZTS1C"}
|
||||
// ITANIUM: [[C88]] = !{i64 88, !"_ZTS1C"}
|
||||
// ITANIUM-DIAG: [[ALL88]] = !{i64 88, !"all-vtables"}
|
||||
// ITANIUM: [[D32]] = !{i64 32, [[D_ID:![0-9]+]]}
|
||||
// ITANIUM: [[D_ID]] = distinct !{}
|
||||
// ITANIUM: [[A64]] = !{i64 64, !"_ZTS1A"}
|
||||
// ITANIUM-DIAG: [[ALL64]] = !{i64 64, !"all-vtables"}
|
||||
// ITANIUM: [[FA16]] = !{i64 16, [[FA_ID:![0-9]+]]}
|
||||
// ITANIUM: [[FA_ID]] = distinct !{}
|
||||
|
||||
// MS: [[A8]] = !{i64 8, !"?AUA@@"}
|
||||
// MS: [[B8]] = !{i64 8, !"?AUB@@"}
|
||||
// MS: [[D8]] = !{i64 8, [[D_ID:![0-9]+]]}
|
||||
// MS: [[D_ID]] = distinct !{}
|
||||
// MS: [[FA8]] = !{i64 8, [[FA_ID:![0-9]+]]}
|
||||
// MS: [[FA_ID]] = distinct !{}
|
Loading…
Reference in New Issue
Block a user