summaryrefslogtreecommitdiff
path: root/src/private_typeinfo.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-07-19 20:19:37 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-07-19 20:19:37 +0000
commit081ea86d80df60bcbb5517868ec5f1afab6bf973 (patch)
tree09943f2017e8e7b3457914f3541c4e81b1bddee9 /src/private_typeinfo.cpp
parente8b3ec33ccb6f76caea7388317d5620b9c36de51 (diff)
[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
Diffstat (limited to 'src/private_typeinfo.cpp')
-rw-r--r--src/private_typeinfo.cpp34
1 files changed, 29 insertions, 5 deletions
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<void**>(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<const __function_type_info*>(__pointee)) {
+ static int (X::*const null_ptr_rep)() = nullptr;
+ adjustedPtr = const_cast<int (X::**)()>(&null_ptr_rep);
+ } else {
+ static int X::*const null_ptr_rep = nullptr;
+ adjustedPtr = const_cast<int X::**>(&null_ptr_rep);
+ }
+ return true;
+ }
+
+ // bullet 1
if (__pbase_type_info::can_catch(thrown_type, adjustedPtr))
return true;