r187948 - UBSan: Fix alignment checks emitted in downcasts.

Filipe Cabecinhas me at filcab.net
Wed Aug 7 18:08:17 PDT 2013


Author: filcab
Date: Wed Aug  7 20:08:17 2013
New Revision: 187948

URL: http://llvm.org/viewvc/llvm-project?rev=187948&view=rev
Log:
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.

Modified:
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=187948&r1=187947&r2=187948&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Aug  7 20:08:17 2013
@@ -2764,18 +2764,18 @@ LValue CodeGenFunction::EmitCastLValue(c
 
     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: {

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=187948&r1=187947&r2=187948&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Wed Aug  7 20:08:17 2013
@@ -1234,15 +1234,18 @@ Value *ScalarExprEmitter::VisitCastExpr(
 
     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: {

Modified: cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp?rev=187948&r1=187947&r2=187948&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp Wed Aug  7 20:08:17 2013
@@ -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 }





More information about the cfe-commits mailing list