summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarshall Clow <mclow.lists@gmail.com>2014-02-06 04:47:02 +0000
committerMarshall Clow <mclow.lists@gmail.com>2014-02-06 04:47:02 +0000
commit98bbf28c5eac8ed3356909563e4d80529507995f (patch)
tree0c04b49d6ab2849d1750a19694826fcf0019608f
parent288859d0a1684e0899702f50353ccdbc1bdab8b7 (diff)
downloadlibcxxabi_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.cpp24
-rw-r--r--test/catch_ptr_02.cpp43
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();
}