//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "private_typeinfo.h" // The flag _LIBCXXABI_FORGIVING_DYNAMIC_CAST is used to make dynamic_cast // more forgiving when type_info's mistakenly have hidden visibility and // thus multiple type_infos can exist for a single type. // // When _LIBCXXABI_FORGIVING_DYNAMIC_CAST is defined, and only in the case where // there is a detected inconsistency in the type_info hierarchy during a // dynamic_cast, then the equality operation will fall back to using strcmp // on type_info names to determine type_info equality. // // This change happens *only* under dynamic_cast, and only when // dynamic_cast is faced with the choice: abort, or possibly give back the // wrong answer. If when the dynamic_cast is done with this fallback // algorithm and an inconsistency is still detected, dynamic_cast will call // abort with an appropriate message. // // The current implementation of _LIBCXXABI_FORGIVING_DYNAMIC_CAST requires a // printf-like function called syslog: // // void syslog(int facility_priority, const char* format, ...); // // If you want this functionality but your platform doesn't have syslog, // just implement it in terms of fprintf(stderr, ...). // // _LIBCXXABI_FORGIVING_DYNAMIC_CAST is currently off by default. // On Windows, typeids are different between DLLs and EXEs, so comparing // type_info* will work for typeids from the same compiled file but fail // for typeids from a DLL and an executable. Among other things, exceptions // are not caught by handlers since can_catch() returns false. // // Defining _LIBCXXABI_FORGIVING_DYNAMIC_CAST does not help since can_catch() calls // is_equal() with use_strcmp=false so the string names are not compared. #include <cstdint> #include <cassert> #include <string.h> #include "abort_message.h" #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST #include <sys/syslog.h> #include <atomic> #endif #if __has_feature(ptrauth_calls) #include <ptrauth.h> #endif template <typename T> static inline T* strip_vtable(T* vtable) { … } static inline bool is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp) { … } static inline ptrdiff_t update_offset_to_base(const char* vtable, ptrdiff_t offset_to_base) { … } namespace __cxxabiv1 { namespace { struct derived_object_info { … }; /// A helper function that gets (dynamic_ptr, dynamic_type, offset_to_derived) from static_ptr. void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr) { … } /// A helper function for __dynamic_cast that casts a base sub-object pointer /// to the object's dynamic type. /// /// This function returns the casting result directly. No further processing /// required. /// /// Specifically, this function can only be called if the following pre- /// condition holds: /// * The dynamic type of the object pointed to by `static_ptr` is exactly /// the same as `dst_type`. const void* dyn_cast_to_derived(const void* static_ptr, const void* dynamic_ptr, const __class_type_info* static_type, const __class_type_info* dst_type, std::ptrdiff_t offset_to_derived, std::ptrdiff_t src2dst_offset) { … } /// A helper function for __dynamic_cast that tries to perform a downcast /// before giving up and falling back to the slow path. const void* dyn_cast_try_downcast(const void* static_ptr, const void* dynamic_ptr, const __class_type_info* dst_type, const __class_type_info* dynamic_type, std::ptrdiff_t src2dst_offset) { … } const void* dyn_cast_slow(const void* static_ptr, const void* dynamic_ptr, const __class_type_info* static_type, const __class_type_info* dst_type, const __class_type_info* dynamic_type, std::ptrdiff_t src2dst_offset) { … } } // namespace // __shim_type_info __shim_type_info::~__shim_type_info() { … } void __shim_type_info::noop1() const { … } void __shim_type_info::noop2() const { … } // __fundamental_type_info // This miraculously (compiler magic) emits the type_info's for: // 1. all of the fundamental types // 2. pointers to all of the fundamental types // 3. pointers to all of the const fundamental types __fundamental_type_info::~__fundamental_type_info() { … } // __array_type_info __array_type_info::~__array_type_info() { … } // __function_type_info __function_type_info::~__function_type_info() { … } // __enum_type_info __enum_type_info::~__enum_type_info() { … } // __class_type_info __class_type_info::~__class_type_info() { … } // __si_class_type_info __si_class_type_info::~__si_class_type_info() { … } // __vmi_class_type_info __vmi_class_type_info::~__vmi_class_type_info() { … } // __pbase_type_info __pbase_type_info::~__pbase_type_info() { … } // __pointer_type_info __pointer_type_info::~__pointer_type_info() { … } // __pointer_to_member_type_info __pointer_to_member_type_info::~__pointer_to_member_type_info() { … } // can_catch // A handler is a match for an exception object of type E if // 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: // // catch (A& a) : adjustedPtr == &a // catch (A* a) : adjustedPtr == a // catch (A** a) : adjustedPtr == a // // 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 __fundamental_type_info::can_catch(const __shim_type_info* thrown_type, void*&) const { … } bool __array_type_info::can_catch(const __shim_type_info*, void*&) const { … } bool __function_type_info::can_catch(const __shim_type_info*, void*&) const { … } // Handles bullet 1 bool __enum_type_info::can_catch(const __shim_type_info* thrown_type, void*&) const { … } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-field-initializers" #endif // Handles bullets 1 and 2 bool __class_type_info::can_catch(const __shim_type_info* thrown_type, void*& adjustedPtr) const { … } #ifdef __clang__ #pragma clang diagnostic pop #endif // When we have an object to inspect - we just pass the pointer to the sub- // object that matched the static_type we just checked. If that is different // from any previously recorded pointer to that object type, then we have // an ambiguous case. // When we have no object to inspect, we need to account for virtual bases // explicitly. // info->vbase_cookie is a pointer to the name of the innermost virtual base // type, or nullptr if there is no virtual base on the path so far. // adjustedPtr points to the subobject we just found. // If vbase_cookie != any previously recorded (including the case of nullptr // representing an already-found static sub-object) then we have an ambiguous // case. Assuming that the vbase_cookie values agree; if then we have a // different offset (adjustedPtr) from any previously recorded, this indicates // an ambiguous case within the virtual base. void __class_type_info::process_found_base_class(__dynamic_cast_info* info, void* adjustedPtr, int path_below) const { … } void __class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, void* adjustedPtr, int path_below) const { … } void __si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, void* adjustedPtr, int path_below) const { … } void __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, void* adjustedPtr, int path_below) const { … } void __vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, void* adjustedPtr, int path_below) const { … } // Handles bullet 1 for both pointers and member pointers bool __pbase_type_info::can_catch(const __shim_type_info* thrown_type, void*&) const { … } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-field-initializers" #endif // Handles bullets 1, 3 and 4 // NOTE: It might not be safe to adjust the pointer if it is not not a pointer // type. Only adjust the pointer after we know it is safe to do so. bool __pointer_type_info::can_catch(const __shim_type_info* thrown_type, void*& adjustedPtr) const { … } bool __pointer_type_info::can_catch_nested( const __shim_type_info* thrown_type) const { … } bool __pointer_to_member_type_info::can_catch( const __shim_type_info* thrown_type, void*& adjustedPtr) const { … } bool __pointer_to_member_type_info::can_catch_nested( const __shim_type_info* thrown_type) const { … } #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-field-initializers" #endif // __dynamic_cast // static_ptr: pointer to an object of type static_type; nonnull, and since the // object is polymorphic, *(void**)static_ptr is a virtual table pointer. // static_ptr is &v in the expression dynamic_cast<T>(v). // static_type: static type of the object pointed to by static_ptr. // dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)"). // src2dst_offset: a static hint about the location of the // source subobject with respect to the complete object; // special negative values are: // -1: no hint // -2: static_type is not a public base of dst_type // -3: static_type is a multiple public base type but never a // virtual base type // otherwise, the static_type type is a unique public nonvirtual // base type of dst_type at offset src2dst_offset from the // origin of dst_type. // // (dynamic_ptr, dynamic_type) are the run time type of the complete object // referred to by static_ptr and a pointer to it. These can be found from // static_ptr for polymorphic types. // static_type is guaranteed to be a polymorphic type. // // (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each // node of the tree represents a base class/object of its parent (or parents) below. // Each node is uniquely represented by a pointer to the object, and a pointer // to a type_info - its type. Different nodes may have the same pointer and // different nodes may have the same type. But only one node has a specific // (pointer-value, type) pair. In C++ two objects of the same type can not // share the same address. // // There are two flavors of nodes which have the type dst_type: // 1. Those that are derived from (below) (static_ptr, static_type). // 2. Those that are not derived from (below) (static_ptr, static_type). // // Invariants of the DAG: // // There is at least one path from the root (dynamic_ptr, dynamic_type) to // the node (static_ptr, static_type). This path may or may not be public. // There may be more than one such path (some public some not). Such a path may // or may not go through a node having type dst_type. // // No node of type T appears above a node of the same type. That means that // there is only one node with dynamic_type. And if dynamic_type == dst_type, // then there is only one dst_type in the DAG. // // No node of type dst_type appears above a node of type static_type. Such // DAG's are possible in C++, but the compiler computes those dynamic_casts at // compile time, and only calls __dynamic_cast when dst_type lies below // static_type in the DAG. // // dst_type != static_type: The compiler computes the dynamic_cast in this case too. // dynamic_type != static_type: The compiler computes the dynamic_cast in this case too. // // Returns: // // If there is exactly one dst_type of flavor 1, and // If there is a public path from that dst_type to (static_ptr, static_type), or // If there are 0 dst_types of flavor 2, and there is a public path from // (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public // path from (dynamic_ptr, dynamic_type) to the one dst_type, then return // a pointer to that dst_type. // Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and // if there is a public path from (dynamic_ptr, dynamic_type) to // (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type) // to the one dst_type, then return a pointer to that one dst_type. // Else return nullptr. // // If dynamic_type == dst_type, then the above algorithm collapses to the // following cheaper algorithm: // // If there is a public path from (dynamic_ptr, dynamic_type) to // (static_ptr, static_type), then return dynamic_ptr. // Else return nullptr. extern "C" _LIBCXXABI_FUNC_VIS void * __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, const __class_type_info *dst_type, std::ptrdiff_t src2dst_offset) { … } #ifdef __clang__ #pragma clang diagnostic pop #endif // Call this function when you hit a static_type which is a base (above) a dst_type. // Let caller know you hit a static_type. But only start recording details if // this is (static_ptr, static_type) -- the node we are casting from. // If this is (static_ptr, static_type) // Record the path (public or not) from the dst_type to here. There may be // multiple paths from the same dst_type to here, record the "most public" one. // Record the dst_ptr as pointing to (static_ptr, static_type). // If more than one (dst_ptr, dst_type) points to (static_ptr, static_type), // then mark this dyanmic_cast as ambiguous and stop the search. void __class_type_info::process_static_type_above_dst(__dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below) const { … } // Call this function when you hit a static_type which is not a base (above) a dst_type. // If this is (static_ptr, static_type) // Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be // multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one. void __class_type_info::process_static_type_below_dst(__dynamic_cast_info* info, const void* current_ptr, int path_below) const { … } // Call this function when searching below a dst_type node. This function searches // for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes. // If it finds a static_type node, there is no need to further search base classes // above. // If it finds a dst_type node it should search base classes using search_above_dst // to find out if this dst_type points to (static_ptr, static_type) or not. // Either way, the dst_type is recorded as one of two "flavors": one that does // or does not point to (static_ptr, static_type). // If this is neither a static_type nor a dst_type node, continue searching // base classes above. // All the hoopla surrounding the search code is doing nothing but looking for // excuses to stop the search prematurely (break out of the for-loop). That is, // the algorithm below is simply an optimization of this: // void // __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, // const void* current_ptr, // int path_below) const // { // typedef const __base_class_type_info* Iter; // if (this == info->static_type) // process_static_type_below_dst(info, current_ptr, path_below); // else if (this == info->dst_type) // { // // Record the most public access path that got us here // if (info->path_dynamic_ptr_to_dst_ptr != public_path) // info->path_dynamic_ptr_to_dst_ptr = path_below; // bool does_dst_type_point_to_our_static_type = false; // for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p) // { // p->search_above_dst(info, current_ptr, current_ptr, public_path); // if (info->found_our_static_ptr) // does_dst_type_point_to_our_static_type = true; // // break out early here if you can detect it doesn't matter if you do // } // if (!does_dst_type_point_to_our_static_type) // { // // We found a dst_type that doesn't point to (static_ptr, static_type) // // So record the address of this dst_ptr and increment the // // count of the number of such dst_types found in the tree. // info->dst_ptr_not_leading_to_static_ptr = current_ptr; // info->number_to_dst_ptr += 1; // } // } // else // { // // This is not a static_type and not a dst_type. // for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p) // { // p->search_below_dst(info, current_ptr, public_path); // // break out early here if you can detect it doesn't matter if you do // } // } // } void __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const { … } // This is the same algorithm as __vmi_class_type_info::search_below_dst but // simplified to the case that there is only a single base class. void __si_class_type_info::search_below_dst(__dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const { … } // This is the same algorithm as __vmi_class_type_info::search_below_dst but // simplified to the case that there is no base class. void __class_type_info::search_below_dst(__dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const { … } // Call this function when searching above a dst_type node. This function searches // for a public path to (static_ptr, static_type). // This function is guaranteed not to find a node of type dst_type. // Theoretically this is a very simple function which just stops if it finds a // static_type node: All the hoopla surrounding the search code is doing // nothing but looking for excuses to stop the search prematurely (break out of // the for-loop). That is, the algorithm below is simply an optimization of this: // void // __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, // const void* dst_ptr, // const void* current_ptr, // int path_below) const // { // if (this == info->static_type) // process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); // else // { // typedef const __base_class_type_info* Iter; // // This is not a static_type and not a dst_type // for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p) // { // p->search_above_dst(info, dst_ptr, current_ptr, public_path); // // break out early here if you can detect it doesn't matter if you do // } // } // } void __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const { … } // This is the same algorithm as __vmi_class_type_info::search_above_dst but // simplified to the case that there is only a single base class. void __si_class_type_info::search_above_dst(__dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const { … } // This is the same algorithm as __vmi_class_type_info::search_above_dst but // simplified to the case that there is no base class. void __class_type_info::search_above_dst(__dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const { … } // The search functions for __base_class_type_info are simply convenience // functions for adjusting the current_ptr and path_below as the search is // passed up to the base class node. void __base_class_type_info::search_above_dst(__dynamic_cast_info* info, const void* dst_ptr, const void* current_ptr, int path_below, bool use_strcmp) const { … } void __base_class_type_info::search_below_dst(__dynamic_cast_info* info, const void* current_ptr, int path_below, bool use_strcmp) const { … } } // __cxxabiv1