Skip to content

Commit

Permalink
CodeGen: Update Clang to use the new type metadata.
Browse files Browse the repository at this point in the history
Differential Revision: http://reviews.llvm.org/D21054

llvm-svn: 273730
  • Loading branch information
pcc committed Jun 24, 2016
1 parent 7efd750 commit 8dd14da
Show file tree
Hide file tree
Showing 22 changed files with 420 additions and 439 deletions.
18 changes: 9 additions & 9 deletions clang/docs/ControlFlowIntegrityDesign.rst
Expand Up @@ -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
Expand Down Expand Up @@ -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
~~~~~~~~~
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
38 changes: 18 additions & 20 deletions clang/lib/CodeGen/CGClass.cpp
Expand Up @@ -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))
Expand Down Expand Up @@ -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) {
Expand All @@ -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});
}

Expand Down
17 changes: 8 additions & 9 deletions clang/lib/CodeGen/CGExpr.cpp
Expand Up @@ -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);

Expand Down Expand Up @@ -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)});
}
Expand Down
13 changes: 5 additions & 8 deletions clang/lib/CodeGen/CGVTables.cpp
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
10 changes: 5 additions & 5 deletions clang/lib/CodeGen/CodeGenFunction.h
Expand Up @@ -1413,15 +1413,15 @@ class CodeGenFunction : public CodeGenTypeCache {
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.
Expand Down
70 changes: 20 additions & 50 deletions clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) &&
Expand All @@ -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);
}
}

Expand Down
26 changes: 12 additions & 14 deletions clang/lib/CodeGen/CodeGenModule.h
Expand Up @@ -1118,29 +1118,27 @@ class CodeGenModule : public CodeGenTypeCache {
/// 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();
Expand Down

0 comments on commit 8dd14da

Please sign in to comment.