From 081ea86d80df60bcbb5517868ec5f1afab6bf973 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 19 Jul 2016 20:19:37 +0000 Subject: [libcxxabi] When catching an exception of type nullptr_t with a handler of pointer-to-member type, produce a null value of the right type. This fixes a bug where throwing an exception of type nullptr_t and catching it as a pointer-to-member would not guarantee to produce a null value in the catch handler. The fix is pretty simple: we statically allocate a constant null pointer-to-data-member representation and a constant null pointer-to-member-function representation, and produce the address of the relevant value as the adjusted pointer for the exception. git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@276016 91177308-0d34-0410-b5e6-96231b3b80d8 --- src/private_typeinfo.cpp | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'src/private_typeinfo.cpp') diff --git a/src/private_typeinfo.cpp b/src/private_typeinfo.cpp index df03596..9804e16 100644 --- a/src/private_typeinfo.cpp +++ b/src/private_typeinfo.cpp @@ -171,8 +171,12 @@ __pointer_to_member_type_info::~__pointer_to_member_type_info() // catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object) // catch (D2* d2) : adjustedPtr == d2 // catch (D2*& d2) : adjustedPtr == d2 -// +// // catch (...) : adjustedPtr == & of the exception +// +// If the thrown type is nullptr_t and the caught type is a pointer to +// member type, adjustedPtr points to a statically-allocated null pointer +// representation of that type. // Handles bullet 1 bool @@ -337,12 +341,11 @@ __vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, } } -// Handles bullets 1 and 4 for both pointers and member pointers +// Handles bullet 1 for both pointers and member pointers bool __pbase_type_info::can_catch(const __shim_type_info* thrown_type, void*&) const { - if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) return true; bool use_strcmp = this->__flags & (__incomplete_class_mask | __incomplete_mask); if (!use_strcmp) { @@ -367,7 +370,13 @@ bool __pointer_type_info::can_catch(const __shim_type_info* thrown_type, void*& adjustedPtr) const { - // bullets 1 and 4 + // bullet 4 + if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) { + adjustedPtr = nullptr; + return true; + } + + // bullet 1 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) { if (adjustedPtr != NULL) adjustedPtr = *static_cast(adjustedPtr); @@ -468,7 +477,22 @@ bool __pointer_type_info::can_catch_nested( bool __pointer_to_member_type_info::can_catch( const __shim_type_info* thrown_type, void*& adjustedPtr) const { - // bullets 1 and 4 + // bullet 4 + if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) { + // We assume that the pointer to member representation is the same for + // all pointers to data members and for all pointers to member functions. + struct X {}; + if (dynamic_cast(__pointee)) { + static int (X::*const null_ptr_rep)() = nullptr; + adjustedPtr = const_cast(&null_ptr_rep); + } else { + static int X::*const null_ptr_rep = nullptr; + adjustedPtr = const_cast(&null_ptr_rep); + } + return true; + } + + // bullet 1 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) return true; -- cgit v1.2.3