aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CGClass.cpp
diff options
context:
space:
mode:
authorNaomi Musgrave <nmusgrave@google.com>2015-09-16 00:38:22 +0000
committerNaomi Musgrave <nmusgrave@google.com>2015-09-16 00:38:22 +0000
commit703835c7f33af043a88b57d01273c9310e7bad7c (patch)
tree4b5114f53850248ecd58a4132d6766f2ab9e1293 /clang/lib/CodeGen/CGClass.cpp
parentc9ca73336dfe3e62d26c8e8e02f817c977b849f4 (diff)
downloadllvm-703835c7f33af043a88b57d01273c9310e7bad7c.zip
llvm-703835c7f33af043a88b57d01273c9310e7bad7c.tar.gz
llvm-703835c7f33af043a88b57d01273c9310e7bad7c.tar.bz2
Implementation and testing for poisoning vtable
ptr in dtor. Summary: After destruction, invocation of virtual functions prevented by poisoning vtable pointer. Reviewers: eugenis, kcc Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D12712 Fixed testing callback emission order to account for vptr. Poison vtable in either complete or base dtor, depending on if virtual bases exist. If virtual bases exist, poison in complete dtor. Otherwise, poison in base. Remove commented-out block. llvm-svn: 247762
Diffstat (limited to 'clang/lib/CodeGen/CGClass.cpp')
-rw-r--r--clang/lib/CodeGen/CGClass.cpp72
1 files changed, 55 insertions, 17 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 7ec9c15..277ee37 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1676,11 +1676,27 @@ namespace {
}
};
- class SanitizeDtor final : public EHScopeStack::Cleanup {
+ static void EmitSanitizerDtorCallback(CodeGenFunction &CGF, llvm::Value *Ptr,
+ CharUnits::QuantityType PoisonSize) {
+ // Pass in void pointer and size of region as arguments to runtime
+ // function
+ llvm::Value *Args[] = {CGF.Builder.CreateBitCast(Ptr, CGF.VoidPtrTy),
+ llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)};
+
+ llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy};
+
+ llvm::FunctionType *FnType =
+ llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false);
+ llvm::Value *Fn =
+ CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback");
+ CGF.EmitNounwindRuntimeCall(Fn, Args);
+ }
+
+ class SanitizeDtorMembers final : public EHScopeStack::Cleanup {
const CXXDestructorDecl *Dtor;
public:
- SanitizeDtor(const CXXDestructorDecl *Dtor) : Dtor(Dtor) {}
+ SanitizeDtorMembers(const CXXDestructorDecl *Dtor) : Dtor(Dtor) {}
// Generate function call for handling object poisoning.
// Disables tail call elimination, to prevent the current stack frame
@@ -1712,11 +1728,11 @@ namespace {
// Currently on the last field, and it must be poisoned with the
// current block.
if (fieldIndex == Layout.getFieldCount() - 1) {
- PoisonBlock(CGF, startIndex, Layout.getFieldCount());
+ PoisonMembers(CGF, startIndex, Layout.getFieldCount());
}
} else if (startIndex >= 0) {
// No longer within a block of memory to poison, so poison the block
- PoisonBlock(CGF, startIndex, fieldIndex);
+ PoisonMembers(CGF, startIndex, fieldIndex);
// Re-set the start index
startIndex = -1;
}
@@ -1729,7 +1745,7 @@ namespace {
/// start poisoning (inclusive)
/// \param layoutEndOffset index of the ASTRecordLayout field to
/// end poisoning (exclusive)
- void PoisonBlock(CodeGenFunction &CGF, unsigned layoutStartOffset,
+ void PoisonMembers(CodeGenFunction &CGF, unsigned layoutStartOffset,
unsigned layoutEndOffset) {
ASTContext &Context = CGF.getContext();
const ASTRecordLayout &Layout =
@@ -1760,20 +1776,30 @@ namespace {
if (PoisonSize == 0)
return;
- // Pass in void pointer and size of region as arguments to runtime
- // function
- llvm::Value *Args[] = {CGF.Builder.CreateBitCast(OffsetPtr, CGF.VoidPtrTy),
- llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)};
+ EmitSanitizerDtorCallback(CGF, OffsetPtr, PoisonSize);
+ }
+ };
+
+ class SanitizeDtorVTable final : public EHScopeStack::Cleanup {
+ const CXXDestructorDecl *Dtor;
+
+ public:
+ SanitizeDtorVTable(const CXXDestructorDecl *Dtor) : Dtor(Dtor) {}
- llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy};
+ // Generate function call for handling vtable pointer poisoning.
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ assert(Dtor->getParent()->isDynamicClass());
+ ASTContext &Context = CGF.getContext();
+ // Poison vtable and vtable ptr if they exist for this class.
+ llvm::Value *VTablePtr = CGF.LoadCXXThis();
- llvm::FunctionType *FnType =
- llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false);
- llvm::Value *Fn =
- CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback");
- CGF.EmitNounwindRuntimeCall(Fn, Args);
+ CharUnits::QuantityType PoisonSize =
+ Context.toCharUnitsFromBits(CGF.PointerWidthInBits).getQuantity();
+ // Pass in void pointer and size of region as arguments to runtime
+ // function
+ EmitSanitizerDtorCallback(CGF, VTablePtr, PoisonSize);
}
- };
+ };
}
/// \brief Emit all code that comes at the end of class's
@@ -1808,6 +1834,12 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
// The complete-destructor phase just destructs all the virtual bases.
if (DtorType == Dtor_Complete) {
+ // Poison the vtable pointer such that access after the base
+ // and member destructors are invoked is invalid.
+ if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
+ SanOpts.has(SanitizerKind::Memory) && ClassDecl->getNumVBases() &&
+ ClassDecl->isPolymorphic())
+ EHStack.pushCleanup<SanitizeDtorVTable>(NormalAndEHCleanup, DD);
// We push them in the forward order so that they'll be popped in
// the reverse order.
@@ -1828,6 +1860,12 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
}
assert(DtorType == Dtor_Base);
+ // Poison the vtable pointer if it has no virtual bases, but inherits
+ // virtual functions.
+ if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
+ SanOpts.has(SanitizerKind::Memory) && !ClassDecl->getNumVBases() &&
+ ClassDecl->isPolymorphic())
+ EHStack.pushCleanup<SanitizeDtorVTable>(NormalAndEHCleanup, DD);
// Destroy non-virtual bases.
for (const auto &Base : ClassDecl->bases()) {
@@ -1850,7 +1888,7 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
// invoked, and before the base class destructor runs, is invalid.
if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
SanOpts.has(SanitizerKind::Memory))
- EHStack.pushCleanup<SanitizeDtor>(NormalAndEHCleanup, DD);
+ EHStack.pushCleanup<SanitizeDtorMembers>(NormalAndEHCleanup, DD);
// Destroy direct fields.
for (const auto *Field : ClassDecl->fields()) {