forked from OSchip/llvm-project
UBSan: Fix alignment checks emitted in downcasts.
Summary: UBSan was checking for alignment of the derived class on the pointer to the base class, before converting. With some class hierarchies, this could generate false positives. Added test-case. llvm-svn: 187948
This commit is contained in:
parent
59c23c0bb5
commit
178a8df660
|
@ -2764,18 +2764,18 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
|||
|
||||
LValue LV = EmitLValue(E->getSubExpr());
|
||||
|
||||
// C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
|
||||
// performed and the object is not of the derived type.
|
||||
if (SanitizePerformTypeCheck)
|
||||
EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
|
||||
LV.getAddress(), E->getType());
|
||||
|
||||
// Perform the base-to-derived conversion
|
||||
llvm::Value *Derived =
|
||||
GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
|
||||
E->path_begin(), E->path_end(),
|
||||
/*NullCheckValue=*/false);
|
||||
|
||||
// C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
|
||||
// performed and the object is not of the derived type.
|
||||
if (SanitizePerformTypeCheck)
|
||||
EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
|
||||
Derived, E->getType());
|
||||
|
||||
return MakeAddrLValue(Derived, E->getType());
|
||||
}
|
||||
case CK_LValueBitCast: {
|
||||
|
|
|
@ -1234,15 +1234,18 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
|
|||
|
||||
llvm::Value *V = Visit(E);
|
||||
|
||||
llvm::Value *Derived =
|
||||
CGF.GetAddressOfDerivedClass(V, DerivedClassDecl,
|
||||
CE->path_begin(), CE->path_end(),
|
||||
ShouldNullCheckClassCastValue(CE));
|
||||
|
||||
// C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is
|
||||
// performed and the object is not of the derived type.
|
||||
if (CGF.SanitizePerformTypeCheck)
|
||||
CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
|
||||
V, DestTy->getPointeeType());
|
||||
Derived, DestTy->getPointeeType());
|
||||
|
||||
return CGF.GetAddressOfDerivedClass(V, DerivedClassDecl,
|
||||
CE->path_begin(), CE->path_end(),
|
||||
ShouldNullCheckClassCastValue(CE));
|
||||
return Derived;
|
||||
}
|
||||
case CK_UncheckedDerivedToBase:
|
||||
case CK_DerivedToBase: {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,bounds -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
|
||||
// RUN: %clang_cc1 -std=c++11 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,bounds -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
|
||||
|
||||
struct S {
|
||||
double d;
|
||||
|
@ -321,4 +321,55 @@ char string_index(int n) {
|
|||
return "Hello"[n];
|
||||
}
|
||||
|
||||
class A // align=4
|
||||
{
|
||||
int a1, a2, a3;
|
||||
};
|
||||
|
||||
class B // align=8
|
||||
{
|
||||
long b1, b2;
|
||||
};
|
||||
|
||||
class C : public A, public B // align=16
|
||||
{
|
||||
alignas(16) int c1;
|
||||
};
|
||||
|
||||
// Make sure we check the alignment of the pointer after subtracting any
|
||||
// offset. The pointer before subtraction doesn't need to be aligned for
|
||||
// the destination type.
|
||||
|
||||
// CHECK-LABEL: define void @_Z16downcast_pointerP1B(%class.B* %b)
|
||||
void downcast_pointer(B *b) {
|
||||
(void) static_cast<C*>(b);
|
||||
// Alignment check from EmitTypeCheck(TCK_DowncastPointer, ...)
|
||||
// CHECK: [[SUB:%sub[.a-z0-9]*]] = getelementptr i8* {{.*}}, i64 -16
|
||||
// CHECK-NEXT: [[C:%[0-9]*]] = bitcast i8* [[SUB]] to %class.C*
|
||||
// null check goes here
|
||||
// CHECK: [[FROM_PHI:%[0-9]*]] = phi %class.C* [ [[C]], %cast.notnull ], {{.*}}
|
||||
// Objectsize check goes here
|
||||
// CHECK: [[C_INT:%[0-9]*]] = ptrtoint %class.C* [[FROM_PHI]] to i64
|
||||
// CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15
|
||||
// CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0
|
||||
// AND the alignment test with the objectsize test.
|
||||
// CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]]
|
||||
// CHECK-NEXT: br i1 [[AND]], label %cont, label %handler.type_mismatch
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @_Z18downcast_referenceR1B(%class.B* %b)
|
||||
void downcast_reference(B &b) {
|
||||
(void) static_cast<C&>(b);
|
||||
// Alignment check from EmitTypeCheck(TCK_DowncastReference, ...)
|
||||
// CHECK: [[SUB:%sub[.a-z0-9]*]] = getelementptr i8* {{.*}}, i64 -16
|
||||
// CHECK-NEXT: [[C:%[0-9]*]] = bitcast i8* [[SUB]] to %class.C*
|
||||
// Objectsize check goes here
|
||||
// CHECK: [[C_INT:%[0-9]*]] = ptrtoint %class.C* [[C]] to i64
|
||||
// CHECK-NEXT: [[MASKED:%[0-9]*]] = and i64 [[C_INT]], 15
|
||||
// CHECK-NEXT: [[TEST:%[0-9]*]] = icmp eq i64 [[MASKED]], 0
|
||||
// AND the alignment test with the objectsize test.
|
||||
// CHECK-NEXT: [[AND:%[0-9]*]] = and i1 {{.*}}, [[TEST]]
|
||||
// CHECK-NEXT: br i1 [[AND]], label %cont, label %handler.type_mismatch
|
||||
}
|
||||
|
||||
// CHECK: attributes [[NR_NUW]] = { noreturn nounwind }
|
||||
|
|
Loading…
Reference in New Issue