diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index f40e435dc51bab0ee391ccb744b8c239775ed1b5..2bf25e7bbc1979db5ef8bf63ea82611cf284b6de 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -201,16 +201,17 @@ __pointer_to_member_type_info::display() const // can_catch // A handler is a match for an exception object of type E if -// * The handler is of type cv T or cv T& and E and T are the same type -// (ignoring the top-level cv-qualifiers), or -// * the handler is of type cv T or cv T& and T is an unambiguous public -// base class of E, or -// * the handler is of type cv1 T* cv2 and E is a pointer type that can be -// converted to the type of the handler by either or both of -// * a standard pointer conversion (4.10) not involving conversions to -// pointers to private or protected or ambiguous classes -// * a qualification conversion -// * the handler is a pointer or pointer to member type and E is std::nullptr_t. +// 1. The handler is of type cv T or cv T& and E and T are the same type +// (ignoring the top-level cv-qualifiers), or +// 2. the handler is of type cv T or cv T& and T is an unambiguous public +// base class of E, or +// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be +// converted to the type of the handler by either or both of +// A. a standard pointer conversion (4.10) not involving conversions to +// pointers to private or protected or ambiguous classes +// B. a qualification conversion +// 4. the handler is a pointer or pointer to member type and E is +// std::nullptr_t. // adjustedPtr: // @@ -233,6 +234,207 @@ __shim_type_info::can_catch(const __shim_type_info* thrown_type, return this == thrown_type; } +// Handles bullet 1 +// TODO: Let __shim_type_info handle it? +bool +__fundamental_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + return this == thrown_type; +} + +bool +__array_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + // TODO: Can this be called? + return false; +} + +bool +__function_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + // TODO: Can this be called? + return false; +} + +// Handles bullet 1 +// TODO: Let __shim_type_info handle it? +bool +__enum_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + return this == thrown_type; +} + +// Handles bullets 1 and 2 +bool +__class_type_info::can_catch(const __shim_type_info* thrown_type, + void*& adjustedPtr) const +{ + // bullet 1 + if (this == thrown_type) + return true; + const __class_type_info* thrown_class_type = + dynamic_cast(thrown_type); + if (thrown_class_type == 0) + return false; + // bullet 2 + __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0}; + info.number_of_dst_type = 1; + thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); + if (info.path_dst_ptr_to_static_ptr == public_path) + { + adjustedPtr = const_cast(info.dst_ptr_leading_to_static_ptr); + return true; + } + return false; +} + +void +__class_type_info::process_found_base_class(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + if (info->dst_ptr_leading_to_static_ptr == 0) + { + // First time here + info->dst_ptr_leading_to_static_ptr = adjustedPtr; + info->path_dst_ptr_to_static_ptr = path_below; + info->number_to_static_ptr = 1; + } + else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr) + { + // We've been here before. Update path to "most public" + if (info->path_dst_ptr_to_static_ptr == not_public_path) + info->path_dst_ptr_to_static_ptr = path_below; + } + else + { + // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr) + // to a static_type + info->number_to_static_ptr += 1; + info->path_dst_ptr_to_static_ptr = not_public_path; + info->search_done = true; + } +} + +void +__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + if (this == info->static_type) + process_found_base_class(info, adjustedPtr, path_below); +} + +void +__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + if (this == info->static_type) + process_found_base_class(info, adjustedPtr, path_below); + else + __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below); +} + +void +__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) + { + const char* vtable = *static_cast(adjustedPtr); + offset_to_base = *reinterpret_cast(vtable + offset_to_base); + } + __base_type->has_unambiguous_public_base(info, + static_cast(adjustedPtr) + offset_to_base, + (__offset_flags & __public_mask) ? + path_below : + not_public_path); +} + +void +__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + if (this == info->static_type) + process_found_base_class(info, adjustedPtr, path_below); + else + { + typedef const __base_class_type_info* Iter; + const Iter e = __base_info + __base_count; + Iter p = __base_info; + p->has_unambiguous_public_base(info, adjustedPtr, path_below); + if (++p < e) + { + do + { + p->has_unambiguous_public_base(info, adjustedPtr, path_below); + if (info->search_done) + break; + } while (++p < e); + } + } +} + +// Handles bullets 1 and 4 +// TODO: Are we good to go here for __pointer_to_member_type_info? +bool +__pbase_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + if (this == thrown_type) + return true; + return thrown_type == &typeid(std::nullptr_t); +} + +// Handles bullets 1, 3 and 4 +bool +__pointer_type_info::can_catch(const __shim_type_info* thrown_type, + void*& adjustedPtr) const +{ + // Do the dereference adjustment + adjustedPtr = *static_cast(adjustedPtr); + // bullets 1 and 4 + if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) + return true; + // bullet 3 + const __pointer_type_info* thrown_pointer_type = + dynamic_cast(thrown_type); + if (thrown_pointer_type == 0) + return false; + // bullet 3B + if (thrown_pointer_type->__flags & ~__flags) + return false; + if (__pointee == thrown_pointer_type->__pointee) + return true; + // bullet 3A + if (__pointee == &typeid(void)) + return true; + const __class_type_info* catch_class_type = + dynamic_cast(__pointee); + if (catch_class_type == 0) + return false; + const __class_type_info* thrown_class_type = + dynamic_cast(thrown_pointer_type->__pointee); + if (thrown_class_type == 0) + return false; + __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0}; + info.number_of_dst_type = 1; + thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); + if (info.path_dst_ptr_to_static_ptr == public_path) + { + adjustedPtr = const_cast(info.dst_ptr_leading_to_static_ptr); + return true; + } + return false; +} #pragma GCC visibility pop #pragma GCC visibility push(default) diff --git a/libcxxabi/src/private_typeinfo.h b/libcxxabi/src/private_typeinfo.h index 501135cd659d79de11f954333e3e608ee9d6c680..9bbd97e677c0aa371dd528e8a7629ed11833ce35 100644 --- a/libcxxabi/src/private_typeinfo.h +++ b/libcxxabi/src/private_typeinfo.h @@ -33,6 +33,7 @@ class __fundamental_type_info { public: virtual ~__fundamental_type_info(); + virtual bool can_catch(const __shim_type_info*, void*&) const; virtual void display() const; }; @@ -41,6 +42,7 @@ class __array_type_info { public: virtual ~__array_type_info(); + virtual bool can_catch(const __shim_type_info*, void*&) const; virtual void display() const; }; @@ -49,6 +51,7 @@ class __function_type_info { public: virtual ~__function_type_info(); + virtual bool can_catch(const __shim_type_info*, void*&) const; virtual void display() const; }; @@ -57,6 +60,7 @@ class __enum_type_info { public: virtual ~__enum_type_info(); + virtual bool can_catch(const __shim_type_info*, void*&) const; virtual void display() const; }; @@ -127,8 +131,11 @@ public: void process_static_type_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; void process_static_type_below_dst(__dynamic_cast_info*, const void*, int) const; + void process_found_base_class(__dynamic_cast_info*, void*, int) const; virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const; + virtual bool can_catch(const __shim_type_info*, void*&) const; + virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; virtual void display() const; }; @@ -143,6 +150,7 @@ public: virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const; + virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; virtual void display() const; }; @@ -161,6 +169,7 @@ public: void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; void search_below_dst(__dynamic_cast_info*, const void*, int) const; + void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; void display() const; }; @@ -185,6 +194,7 @@ public: virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const; + virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; virtual void display() const; }; @@ -205,6 +215,7 @@ public: }; virtual ~__pbase_type_info(); + virtual bool can_catch(const __shim_type_info*, void*&) const; }; class __pointer_type_info @@ -212,6 +223,7 @@ class __pointer_type_info { public: virtual ~__pointer_type_info(); + virtual bool can_catch(const __shim_type_info*, void*&) const; virtual void display() const; };