[compiler-rt] r221445 - UBSan: Teach isDerivedFromAtOffset and findBaseAtOffset about vbases

David Majnemer david.majnemer at gmail.com
Thu Nov 6 00:55:23 PST 2014


Author: majnemer
Date: Thu Nov  6 02:55:23 2014
New Revision: 221445

URL: http://llvm.org/viewvc/llvm-project?rev=221445&view=rev
Log:
UBSan: Teach isDerivedFromAtOffset and findBaseAtOffset about vbases

When the __virtual_mask is set, __offset_flags >> __offset_shift yields
an offset into the vtable.  Dereferencing this vtable slot gets us the
vbase offset.

Adjust a test case to verify that this, in fact, works.

Differential Revision: http://reviews.llvm.org/D6074

Modified:
    compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc
    compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp

Modified: compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc?rev=221445&r1=221444&r2=221445&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash.cc Thu Nov  6 02:55:23 2014
@@ -115,7 +115,8 @@ __ubsan::__ubsan_vptr_type_cache[__ubsan
 
 /// \brief Determine whether \p Derived has a \p Base base class subobject at
 /// offset \p Offset.
-static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
+static bool isDerivedFromAtOffset(sptr Object,
+                                  const abi::__class_type_info *Derived,
                                   const abi::__class_type_info *Base,
                                   sptr Offset) {
   if (Derived->__type_name == Base->__type_name)
@@ -123,7 +124,7 @@ static bool isDerivedFromAtOffset(const
 
   if (const abi::__si_class_type_info *SI =
         dynamic_cast<const abi::__si_class_type_info*>(Derived))
-    return isDerivedFromAtOffset(SI->__base_type, Base, Offset);
+    return isDerivedFromAtOffset(Object, SI->__base_type, Base, Offset);
 
   const abi::__vmi_class_type_info *VTI =
     dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
@@ -138,13 +139,13 @@ static bool isDerivedFromAtOffset(const
     sptr OffsetHere = VTI->base_info[base].__offset_flags >>
                       abi::__base_class_type_info::__offset_shift;
     if (VTI->base_info[base].__offset_flags &
-          abi::__base_class_type_info::__virtual_mask)
-      // For now, just punt on virtual bases and say 'yes'.
-      // FIXME: OffsetHere is the offset in the vtable of the virtual base
-      //        offset. Read the vbase offset out of the vtable and use it.
-      return true;
-    if (isDerivedFromAtOffset(VTI->base_info[base].__base_type,
-                              Base, Offset - OffsetHere))
+          abi::__base_class_type_info::__virtual_mask) {
+      sptr VTable = *reinterpret_cast<const sptr *>(Object);
+      OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere);
+    }
+    if (isDerivedFromAtOffset(Object + OffsetHere,
+                              VTI->base_info[base].__base_type, Base,
+                              Offset - OffsetHere))
       return true;
   }
 
@@ -153,14 +154,15 @@ static bool isDerivedFromAtOffset(const
 
 /// \brief Find the derived-most dynamic base class of \p Derived at offset
 /// \p Offset.
-static const abi::__class_type_info *findBaseAtOffset(
-    const abi::__class_type_info *Derived, sptr Offset) {
+static const abi::__class_type_info *
+findBaseAtOffset(sptr Object, const abi::__class_type_info *Derived,
+                 sptr Offset) {
   if (!Offset)
     return Derived;
 
   if (const abi::__si_class_type_info *SI =
         dynamic_cast<const abi::__si_class_type_info*>(Derived))
-    return findBaseAtOffset(SI->__base_type, Offset);
+    return findBaseAtOffset(Object, SI->__base_type, Offset);
 
   const abi::__vmi_class_type_info *VTI =
     dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
@@ -172,12 +174,13 @@ static const abi::__class_type_info *fin
     sptr OffsetHere = VTI->base_info[base].__offset_flags >>
                       abi::__base_class_type_info::__offset_shift;
     if (VTI->base_info[base].__offset_flags &
-          abi::__base_class_type_info::__virtual_mask)
-      // FIXME: Can't handle virtual bases yet.
-      continue;
-    if (const abi::__class_type_info *Base =
-          findBaseAtOffset(VTI->base_info[base].__base_type,
-                           Offset - OffsetHere))
+          abi::__base_class_type_info::__virtual_mask) {
+      sptr VTable = *reinterpret_cast<const sptr *>(Object);
+      OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere);
+    }
+    if (const abi::__class_type_info *Base = findBaseAtOffset(
+            Object + OffsetHere, VTI->base_info[base].__base_type,
+            Offset - OffsetHere))
       return Base;
   }
 
@@ -229,7 +232,8 @@ bool __ubsan::checkDynamicType(void *Obj
     return false;
 
   abi::__class_type_info *Base = (abi::__class_type_info*)Type;
-  if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset))
+  if (!isDerivedFromAtOffset(reinterpret_cast<sptr>(Object), Derived, Base,
+                             -Vtable->Offset))
     return false;
 
   // Success. Cache this result.
@@ -243,8 +247,9 @@ __ubsan::DynamicTypeInfo __ubsan::getDyn
   if (!Vtable)
     return DynamicTypeInfo(0, 0, 0);
   const abi::__class_type_info *ObjectType = findBaseAtOffset(
-    static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
-    -Vtable->Offset);
+      reinterpret_cast<sptr>(Object),
+      static_cast<const abi::__class_type_info *>(Vtable->TypeInfo),
+      -Vtable->Offset);
   return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,
                          ObjectType ? ObjectType->__type_name : "<unknown>");
 }

Modified: compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp?rev=221445&r1=221444&r2=221445&view=diff
==============================================================================
--- compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp (original)
+++ compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp Thu Nov  6 02:55:23 2014
@@ -48,7 +48,8 @@ struct T : S {
   virtual int v() { return 1; }
 };
 
-struct U : S, T { virtual int v() { return 2; } };
+struct X {};
+struct U : S, T, virtual X { virtual int v() { return 2; } };
 
 struct V : S {};
 





More information about the llvm-commits mailing list