r321519 - -fsanitize=vptr warnings on bad static types in dynamic_cast and typeid
Stephan Bergmann via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 28 04:45:42 PST 2017
Author: sberg
Date: Thu Dec 28 04:45:41 2017
New Revision: 321519
URL: http://llvm.org/viewvc/llvm-project?rev=321519&view=rev
Log:
-fsanitize=vptr warnings on bad static types in dynamic_cast and typeid
...when such an operation is done on an object during con-/destruction.
This is the cfe part of a patch covering both cfe and compiler-rt.
Differential Revision: https://reviews.llvm.org/D40295
Modified:
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGenCXX/ubsan-vtable-checks.cpp
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=321519&r1=321518&r2=321519&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Dec 28 04:45:41 2017
@@ -570,7 +570,7 @@ static llvm::Value *emitHash16Bytes(CGBu
bool CodeGenFunction::isNullPointerAllowed(TypeCheckKind TCK) {
return TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
- TCK == TCK_UpcastToVirtualBase;
+ TCK == TCK_UpcastToVirtualBase || TCK == TCK_DynamicOperation;
}
bool CodeGenFunction::isVptrCheckRequired(TypeCheckKind TCK, QualType Ty) {
@@ -578,7 +578,7 @@ bool CodeGenFunction::isVptrCheckRequire
return (RD && RD->hasDefinition() && RD->isDynamicClass()) &&
(TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference ||
- TCK == TCK_UpcastToVirtualBase);
+ TCK == TCK_UpcastToVirtualBase || TCK == TCK_DynamicOperation);
}
bool CodeGenFunction::sanitizePerformTypeCheck() const {
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=321519&r1=321518&r2=321519&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Thu Dec 28 04:45:41 2017
@@ -2056,6 +2056,15 @@ static llvm::Value *EmitTypeidFromVTable
// Get the vtable pointer.
Address ThisPtr = CGF.EmitLValue(E).getAddress();
+ QualType SrcRecordTy = E->getType();
+
+ // C++ [class.cdtor]p4:
+ // If the operand of typeid refers to the object under construction or
+ // destruction and the static type of the operand is neither the constructor
+ // or destructorâs class nor one of its bases, the behavior is undefined.
+ CGF.EmitTypeCheck(CodeGenFunction::TCK_DynamicOperation, E->getExprLoc(),
+ ThisPtr.getPointer(), SrcRecordTy);
+
// C++ [expr.typeid]p2:
// If the glvalue expression is obtained by applying the unary * operator to
// a pointer and the pointer is a null pointer value, the typeid expression
@@ -2064,7 +2073,6 @@ static llvm::Value *EmitTypeidFromVTable
// However, this paragraph's intent is not clear. We choose a very generous
// interpretation which implores us to consider comma operators, conditional
// operators, parentheses and other such constructs.
- QualType SrcRecordTy = E->getType();
if (CGF.CGM.getCXXABI().shouldTypeidBeNullChecked(
isGLValueFromPointerDeref(E), SrcRecordTy)) {
llvm::BasicBlock *BadTypeidBlock =
@@ -2127,10 +2135,6 @@ llvm::Value *CodeGenFunction::EmitDynami
CGM.EmitExplicitCastExprType(DCE, this);
QualType DestTy = DCE->getTypeAsWritten();
- if (DCE->isAlwaysNull())
- if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
- return T;
-
QualType SrcTy = DCE->getSubExpr()->getType();
// C++ [expr.dynamic.cast]p7:
@@ -2151,6 +2155,18 @@ llvm::Value *CodeGenFunction::EmitDynami
DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
}
+ // C++ [class.cdtor]p5:
+ // If the operand of the dynamic_cast refers to the object under
+ // construction or destruction and the static type of the operand is not a
+ // pointer to or object of the constructor or destructorâs own class or one
+ // of its bases, the dynamic_cast results in undefined behavior.
+ EmitTypeCheck(TCK_DynamicOperation, DCE->getExprLoc(), ThisAddr.getPointer(),
+ SrcRecordTy);
+
+ if (DCE->isAlwaysNull())
+ if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
+ return T;
+
assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
// C++ [expr.dynamic.cast]p4:
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=321519&r1=321518&r2=321519&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Dec 28 04:45:41 2017
@@ -2371,7 +2371,10 @@ public:
/// object within its lifetime.
TCK_UpcastToVirtualBase,
/// Checking the value assigned to a _Nonnull pointer. Must not be null.
- TCK_NonnullAssign
+ TCK_NonnullAssign,
+ /// Checking the operand of a dynamic_cast or a typeid expression. Must be
+ /// null or an object within its lifetime.
+ TCK_DynamicOperation
};
/// Determine whether the pointer type check \p TCK permits null pointers.
Modified: cfe/trunk/test/CodeGenCXX/ubsan-vtable-checks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/ubsan-vtable-checks.cpp?rev=321519&r1=321518&r2=321519&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/ubsan-vtable-checks.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/ubsan-vtable-checks.cpp Thu Dec 28 04:45:41 2017
@@ -38,3 +38,15 @@ void delete_it(T *t) {
// CHECK-VPTR: load {{.*}} (%struct.T*{{.*}})**, {{.*}} (%struct.T*{{.*}})***
delete t;
}
+
+// ITANIUM: define %struct.U* @_Z7dyncastP1T
+// MSABI: define %struct.U* @"\01?dyncast
+U* dyncast(T *t) {
+ // First, we check that dynamic_cast is not called before a type check.
+ // CHECK-VPTR-NOT: call i8* @__{{dynamic_cast|RTDynamicCast}}
+ // CHECK-VPTR: br i1 {{.*}} label %{{.*}}
+ // CHECK-VPTR: call void @__ubsan_handle_dynamic_type_cache_miss_abort
+ // Second, we check that dynamic_cast is actually called once the type check is done.
+ // CHECK-VPTR: call i8* @__{{dynamic_cast|RTDynamicCast}}
+ return dynamic_cast<U*>(t);
+}
More information about the cfe-commits
mailing list