diff options
author | Marshall Clow <mclow.lists@gmail.com> | 2014-02-06 04:47:02 +0000 |
---|---|---|
committer | Marshall Clow <mclow.lists@gmail.com> | 2014-02-06 04:47:02 +0000 |
commit | 98bbf28c5eac8ed3356909563e4d80529507995f (patch) | |
tree | 0c04b49d6ab2849d1750a19694826fcf0019608f | |
parent | 288859d0a1684e0899702f50353ccdbc1bdab8b7 (diff) | |
download | libcxxabi_35a-98bbf28c5eac8ed3356909563e4d80529507995f.tar.gz |
Fix PR17221 - can't catch virtual base classes when throwing derived NULL pointers. Specifically, libc++abi would crash when you tried it.
git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@200904 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | src/private_typeinfo.cpp | 24 | ||||
-rw-r--r-- | test/catch_ptr_02.cpp | 43 |
2 files changed, 53 insertions, 14 deletions
diff --git a/src/private_typeinfo.cpp b/src/private_typeinfo.cpp index 2dafdfb..c65dcab 100644 --- a/src/private_typeinfo.cpp +++ b/src/private_typeinfo.cpp @@ -301,17 +301,20 @@ __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, void* adjustedPtr, int path_below) const { - ptrdiff_t offset_to_base = __offset_flags >> __offset_shift; - if (__offset_flags & __virtual_mask) + ptrdiff_t offset_to_base = 0; + if (adjustedPtr != nullptr) { - const char* vtable = *static_cast<const char*const*>(adjustedPtr); - offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); + offset_to_base = __offset_flags >> __offset_shift; + if (__offset_flags & __virtual_mask) + { + const char* vtable = *static_cast<const char*const*>(adjustedPtr); + offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); + } } - __base_type->has_unambiguous_public_base(info, - static_cast<char*>(adjustedPtr) + offset_to_base, - (__offset_flags & __public_mask) ? - path_below : - not_public_path); + __base_type->has_unambiguous_public_base( + info, + static_cast<char*>(adjustedPtr) + offset_to_base, + (__offset_flags & __public_mask) ? path_below : not_public_path); } void @@ -358,7 +361,8 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type, void*& adjustedPtr) const { // Do the dereference adjustment - adjustedPtr = *static_cast<void**>(adjustedPtr); + if (adjustedPtr != NULL) + adjustedPtr = *static_cast<void**>(adjustedPtr); // bullets 1 and 4 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) return true; diff --git a/test/catch_ptr_02.cpp b/test/catch_ptr_02.cpp index e858c9f..9421782 100644 --- a/test/catch_ptr_02.cpp +++ b/test/catch_ptr_02.cpp @@ -130,17 +130,49 @@ void test7 () } -struct vA {}; -struct vC : virtual public vA {}; +struct vBase {}; +struct vDerived : virtual public vBase {}; void test8 () { try { - throw (vC*)0; + throw new vDerived; assert(false); } - catch (vA *p) { + catch (vBase *p) { + assert(p != 0); + } + catch (...) + { + assert (false); + } +} + +void test9 () +{ + try + { + throw nullptr; + assert(false); + } + catch (vBase *p) { + assert(p == 0); + } + catch (...) + { + assert (false); + } +} + +void test10 () +{ + try + { + throw (vDerived*)0; + assert(false); + } + catch (vBase *p) { assert(p == 0); } catch (...) @@ -158,4 +190,7 @@ int main() test5(); test6(); test7(); + test8(); + test9(); + test10(); } |