From 3400563ea6160dce01a0fb4741bacc4b61db74ad Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Thu, 6 Nov 2014 08:55:23 +0000 Subject: [PATCH] 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 llvm-svn: 221445 --- compiler-rt/lib/ubsan/ubsan_type_hash.cc | 47 ++++++++++++---------- .../test/ubsan/TestCases/TypeCheck/vptr.cpp | 3 +- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/compiler-rt/lib/ubsan/ubsan_type_hash.cc b/compiler-rt/lib/ubsan/ubsan_type_hash.cc index a388bcc..808a433 100644 --- a/compiler-rt/lib/ubsan/ubsan_type_hash.cc +++ b/compiler-rt/lib/ubsan/ubsan_type_hash.cc @@ -115,7 +115,8 @@ __ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize]; /// \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 abi::__class_type_info *Derived, if (const abi::__si_class_type_info *SI = dynamic_cast(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(Derived); @@ -138,13 +139,13 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, 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(Object); + OffsetHere = *reinterpret_cast(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 abi::__class_type_info *Derived, /// \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(Derived)) - return findBaseAtOffset(SI->__base_type, Offset); + return findBaseAtOffset(Object, SI->__base_type, Offset); const abi::__vmi_class_type_info *VTI = dynamic_cast(Derived); @@ -172,12 +174,13 @@ static const abi::__class_type_info *findBaseAtOffset( 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(Object); + OffsetHere = *reinterpret_cast(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 *Object, void *Type, HashValue Hash) { return false; abi::__class_type_info *Base = (abi::__class_type_info*)Type; - if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset)) + if (!isDerivedFromAtOffset(reinterpret_cast(Object), Derived, Base, + -Vtable->Offset)) return false; // Success. Cache this result. @@ -243,8 +247,9 @@ __ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) { if (!Vtable) return DynamicTypeInfo(0, 0, 0); const abi::__class_type_info *ObjectType = findBaseAtOffset( - static_cast(Vtable->TypeInfo), - -Vtable->Offset); + reinterpret_cast(Object), + static_cast(Vtable->TypeInfo), + -Vtable->Offset); return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset, ObjectType ? ObjectType->__type_name : ""); } diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr.cpp index 1e1d67a..3a6b155 100644 --- a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr.cpp +++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -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 {}; -- 2.7.4