[cfe-commits] r166661 - in /cfe/trunk/lib: CodeGen/CGExpr.cpp CodeGen/CGExprCXX.cpp CodeGen/CodeGenFunction.h Driver/Tools.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Wed Oct 24 19:14:13 PDT 2012
Author: rsmith
Date: Wed Oct 24 21:14:12 2012
New Revision: 166661
URL: http://llvm.org/viewvc/llvm-project?rev=166661&view=rev
Log:
-fcatch-undefined-behavior checking for appropriate vptr value: Clang CodeGen side.
Modified:
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/Driver/Tools.cpp
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=166661&r1=166660&r2=166661&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Oct 24 21:14:12 2012
@@ -27,6 +27,7 @@
#include "llvm/LLVMContext.h"
#include "llvm/MDBuilder.h"
#include "llvm/DataLayout.h"
+#include "llvm/ADT/Hashing.h"
using namespace clang;
using namespace CodeGen;
@@ -558,6 +559,18 @@
->getZExtValue();
}
+/// Emit the hash_16_bytes function from include/llvm/ADT/Hashing.h.
+static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low,
+ llvm::Value *High) {
+ llvm::Value *KMul = Builder.getInt64(0x9ddfea08eb382d69ULL);
+ llvm::Value *K47 = Builder.getInt64(47);
+ llvm::Value *A0 = Builder.CreateMul(Builder.CreateXor(Low, High), KMul);
+ llvm::Value *A1 = Builder.CreateXor(Builder.CreateLShr(A0, K47), A0);
+ llvm::Value *B0 = Builder.CreateMul(Builder.CreateXor(High, A1), KMul);
+ llvm::Value *B1 = Builder.CreateXor(Builder.CreateLShr(B0, K47), B0);
+ return Builder.CreateMul(B1, KMul);
+}
+
void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::Value *Address,
QualType Ty, CharUnits Alignment) {
@@ -613,6 +626,62 @@
};
EmitCheck(Cond, "type_mismatch", StaticData, Address);
}
+
+ CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (TCK != TCK_ConstructorCall &&
+ RD && RD->hasDefinition() && RD->isDynamicClass()) {
+ // Check that the vptr indicates that there is a subobject of type Ty at
+ // offset zero within this object.
+ // FIXME: Produce a diagnostic if the user tries to combine this check with
+ // -fno-rtti.
+
+ // Compute a hash of the mangled name of the type.
+ //
+ // FIXME: This is not guaranteed to be deterministic! Move to a
+ // fingerprinting mechanism once LLVM provides one. For the time
+ // being the implementation happens to be deterministic.
+ llvm::SmallString<64> MangledName;
+ llvm::raw_svector_ostream Out(MangledName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(),
+ Out);
+ llvm::hash_code TypeHash = hash_value(Out.str());
+
+ // Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
+ llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash);
+ llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0);
+ llvm::Value *VPtrAddr = Builder.CreateBitCast(Address, VPtrTy);
+ llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr);
+ llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty);
+
+ llvm::Value *Hash = emitHash16Bytes(Builder, Low, High);
+ Hash = Builder.CreateTrunc(Hash, IntPtrTy);
+
+ // Look the hash up in our cache.
+ const int CacheSize = 128;
+ llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize);
+ llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable,
+ "__ubsan_vptr_type_cache");
+ llvm::Value *Slot = Builder.CreateAnd(Hash,
+ llvm::ConstantInt::get(IntPtrTy,
+ CacheSize-1));
+ llvm::Value *Indices[] = { Builder.getInt32(0), Slot };
+ llvm::Value *CacheVal =
+ Builder.CreateLoad(Builder.CreateInBoundsGEP(Cache, Indices));
+
+ // If the hash isn't in the cache, call a runtime handler to perform the
+ // hard work of checking whether the vptr is for an object of the right
+ // type. This will either fill in the cache and return, or produce a
+ // diagnostic.
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty),
+ CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()),
+ llvm::ConstantInt::get(Int8Ty, TCK)
+ };
+ llvm::Value *DynamicData[] = { Address, Hash };
+ EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
+ "dynamic_type_cache_miss", StaticData, DynamicData, true);
+ }
}
@@ -2042,7 +2111,8 @@
void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
llvm::ArrayRef<llvm::Constant *> StaticArgs,
- llvm::ArrayRef<llvm::Value *> DynamicArgs) {
+ llvm::ArrayRef<llvm::Value *> DynamicArgs,
+ bool Recoverable) {
llvm::BasicBlock *Cont = createBasicBlock("cont");
// If -fcatch-undefined-behavior is not enabled, just emit a trap. This
@@ -2096,17 +2166,23 @@
llvm::FunctionType *FnType =
llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
llvm::AttrBuilder B;
- B.addAttribute(llvm::Attributes::NoReturn)
- .addAttribute(llvm::Attributes::NoUnwind)
- .addAttribute(llvm::Attributes::UWTable);
+ if (!Recoverable) {
+ B.addAttribute(llvm::Attributes::NoReturn)
+ .addAttribute(llvm::Attributes::NoUnwind);
+ }
+ B.addAttribute(llvm::Attributes::UWTable);
llvm::Value *Fn = CGM.CreateRuntimeFunction(FnType,
("__ubsan_handle_" + CheckName).str(),
llvm::Attributes::get(getLLVMContext(),
B));
llvm::CallInst *HandlerCall = Builder.CreateCall(Fn, Args);
- HandlerCall->setDoesNotReturn();
- HandlerCall->setDoesNotThrow();
- Builder.CreateUnreachable();
+ if (Recoverable) {
+ Builder.CreateBr(Cont);
+ } else {
+ HandlerCall->setDoesNotReturn();
+ HandlerCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+ }
EmitBlock(Cont);
}
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=166661&r1=166660&r2=166661&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Oct 24 21:14:12 2012
@@ -37,8 +37,9 @@
// C++11 [class.mfct.non-static]p2:
// If a non-static member function of a class X is called for an object that
// is not of type X, or of a type derived from X, the behavior is undefined.
- EmitTypeCheck(TCK_MemberCall, CallLoc, This,
- getContext().getRecordType(MD->getParent()));
+ EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
+ : TCK_MemberCall,
+ CallLoc, This, getContext().getRecordType(MD->getParent()));
CallArgList Args;
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=166661&r1=166660&r2=166661&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Oct 24 21:14:12 2012
@@ -1871,7 +1871,9 @@
TCK_MemberAccess,
/// Checking the 'this' pointer for a call to a non-static member function.
/// Must be an object within its lifetime.
- TCK_MemberCall
+ TCK_MemberCall,
+ /// Checking the 'this' pointer for a constructor call.
+ TCK_ConstructorCall
};
/// \brief Emit a check that \p V is the address of storage of the
@@ -2576,7 +2578,8 @@
/// conditional branch to it.
void EmitCheck(llvm::Value *Checked, StringRef CheckName,
llvm::ArrayRef<llvm::Constant *> StaticArgs,
- llvm::ArrayRef<llvm::Value *> DynamicArgs);
+ llvm::ArrayRef<llvm::Value *> DynamicArgs,
+ bool Recoverable = false);
/// EmitCallArg - Emit a single call argument.
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=166661&r1=166660&r2=166661&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Wed Oct 24 21:14:12 2012
@@ -5914,6 +5914,9 @@
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+ // Call this before we add the C++ ABI library.
+ addUbsanRTLinux(getToolChain(), Args, CmdArgs);
+
if (D.CCCIsCXX &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -5966,7 +5969,6 @@
}
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
- addUbsanRTLinux(getToolChain(), Args, CmdArgs);
C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
}
More information about the cfe-commits
mailing list