1548 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "private_typeinfo.h"10 11// The flag _LIBCXXABI_FORGIVING_DYNAMIC_CAST is used to make dynamic_cast12// more forgiving when type_info's mistakenly have hidden visibility and13// thus multiple type_infos can exist for a single type.14//15// When _LIBCXXABI_FORGIVING_DYNAMIC_CAST is defined, and only in the case where16// there is a detected inconsistency in the type_info hierarchy during a17// dynamic_cast, then the equality operation will fall back to using strcmp18// on type_info names to determine type_info equality.19//20// This change happens *only* under dynamic_cast, and only when21// dynamic_cast is faced with the choice: abort, or possibly give back the22// wrong answer. If when the dynamic_cast is done with this fallback23// algorithm and an inconsistency is still detected, dynamic_cast will call24// abort with an appropriate message.25//26// The current implementation of _LIBCXXABI_FORGIVING_DYNAMIC_CAST requires a27// printf-like function called syslog:28//29// void syslog(int facility_priority, const char* format, ...);30//31// If you want this functionality but your platform doesn't have syslog,32// just implement it in terms of fprintf(stderr, ...).33//34// _LIBCXXABI_FORGIVING_DYNAMIC_CAST is currently off by default.35 36// On Windows, typeids are different between DLLs and EXEs, so comparing37// type_info* will work for typeids from the same compiled file but fail38// for typeids from a DLL and an executable. Among other things, exceptions39// are not caught by handlers since can_catch() returns false.40//41// Defining _LIBCXXABI_FORGIVING_DYNAMIC_CAST does not help since can_catch() calls42// is_equal() with use_strcmp=false so the string names are not compared.43 44#include <cassert>45#include <cstddef>46#include <cstdint>47#include <string.h>48 49#include "abort_message.h"50 51#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST52#include <sys/syslog.h>53#include <atomic>54#endif55 56#if __has_feature(ptrauth_calls)57#include <ptrauth.h>58#endif59 60template <typename T>61static inline T* strip_vtable(T* vtable) {62#if __has_feature(ptrauth_calls)63 vtable = ptrauth_strip(vtable, ptrauth_key_cxx_vtable_pointer);64#endif65 return vtable;66}67 68static inline69bool70is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp)71{72 // Use std::type_info's default comparison unless we've explicitly asked73 // for strcmp.74 if (!use_strcmp)75 return *x == *y;76 // Still allow pointer equality to short circut.77 return x == y || strcmp(x->name(), y->name()) == 0;78}79 80static inline ptrdiff_t update_offset_to_base(const char* vtable,81 ptrdiff_t offset_to_base) {82#if __has_feature(cxx_abi_relative_vtable)83 // VTable components are 32 bits in the relative vtables ABI.84 return *reinterpret_cast<const int32_t*>(vtable + offset_to_base);85#else86 return *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);87#endif88}89 90namespace __cxxabiv191{92 93namespace {94 95struct derived_object_info {96 const void* dynamic_ptr;97 const __class_type_info* dynamic_type;98 std::ptrdiff_t offset_to_derived;99};100 101/// A helper function that gets (dynamic_ptr, dynamic_type, offset_to_derived) from static_ptr.102void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr)103{104#if __has_feature(cxx_abi_relative_vtable)105 // The vtable address will point to the first virtual function, which is 8106 // bytes after the start of the vtable (4 for the offset from top + 4 for107 // the typeinfo component).108 const int32_t* vtable =109 *reinterpret_cast<const int32_t* const*>(static_ptr);110 info->offset_to_derived = static_cast<std::ptrdiff_t>(vtable[-2]);111 info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;112 113 // The typeinfo component is now a relative offset to a proxy.114 int32_t offset_to_ti_proxy = vtable[-1];115 const uint8_t* ptr_to_ti_proxy =116 reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy;117 info->dynamic_type = *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));118#else119 void** vtable = strip_vtable(*static_cast<void** const*>(static_ptr));120 info->offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);121 info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;122 info->dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);123#endif124}125 126/// A helper function for __dynamic_cast that casts a base sub-object pointer127/// to the object's dynamic type.128///129/// This function returns the casting result directly. No further processing130/// required.131///132/// Specifically, this function can only be called if the following pre-133/// condition holds:134/// * The dynamic type of the object pointed to by `static_ptr` is exactly135/// the same as `dst_type`.136const void* dyn_cast_to_derived(const void* static_ptr,137 const void* dynamic_ptr,138 const __class_type_info* static_type,139 const __class_type_info* dst_type,140 std::ptrdiff_t offset_to_derived,141 std::ptrdiff_t src2dst_offset)142{143 // We're downcasting from src_type to the complete object's dynamic type.144 // This is a really hot path that can be further optimized with the145 // `src2dst_offset` hint.146 // In such a case, dynamic_ptr already gives the casting result if the147 // casting ever succeeds. All we have to do now is to check static_ptr148 // points to a public base sub-object of dynamic_ptr.149 150 if (src2dst_offset >= 0)151 {152 // The static type is a unique public non-virtual base type of153 // dst_type at offset `src2dst_offset` from the origin of dst.154 // Note that there might be other non-public static_type bases. The155 // hint only guarantees that the public base is non-virtual and156 // unique. So we have to check whether static_ptr points to that157 // unique public base sub-object.158 if (offset_to_derived != -src2dst_offset)159 return nullptr;160 return dynamic_ptr;161 }162 163 if (src2dst_offset == -2)164 {165 // static_type is not a public base of dst_type.166 return nullptr;167 }168 169 // If src2dst_offset == -3, then:170 // src_type is a multiple public base type but never a virtual171 // base type. We can't conclude that static_ptr points to those172 // public base sub-objects because there might be other non-173 // public static_type bases. The search is inevitable.174 175 // Fallback to the slow path to check that static_type is a public176 // base type of dynamic_type.177 // Using giant short cut. Add that information to info.178 __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0,179 1, // number_of_dst_type180 false, false, false, true, nullptr};181 // Do the search182 dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);183#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST184 // The following if should always be false because we should185 // definitely find (static_ptr, static_type), either on a public186 // or private path187 if (info.path_dst_ptr_to_static_ptr == unknown)188 {189 // We get here only if there is some kind of visibility problem190 // in client code.191 static_assert(std::atomic<size_t>::is_always_lock_free, "");192 static std::atomic<size_t> error_count(0);193 size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);194 if ((error_count_snapshot & (error_count_snapshot-1)) == 0)195 syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "196 "should have public visibility. At least one of them is hidden. %s"197 ", %s.\n", static_type->name(), dst_type->name());198 // Redo the search comparing type_info's using strcmp199 info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,200 0, 0, 0, false, false, false, true, nullptr};201 info.number_of_dst_type = 1;202 dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);203 }204#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST205 // Query the search.206 if (info.path_dst_ptr_to_static_ptr != public_path)207 return nullptr;208 209 return dynamic_ptr;210}211 212/// A helper function for __dynamic_cast that tries to perform a downcast213/// before giving up and falling back to the slow path.214const void* dyn_cast_try_downcast(const void* static_ptr,215 const void* dynamic_ptr,216 const __class_type_info* dst_type,217 const __class_type_info* dynamic_type,218 std::ptrdiff_t src2dst_offset)219{220 if (src2dst_offset < 0)221 {222 // We can only optimize the case if the static type is a unique public223 // base of dst_type. Give up.224 return nullptr;225 }226 227 // Pretend there is a dst_type object that leads to static_ptr. Later we228 // will check whether this imagined dst_type object exists. If it exists229 // then it will be the casting result.230 const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset;231 232 if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) < reinterpret_cast<std::intptr_t>(dynamic_ptr))233 {234 // The imagined dst_type object does not exist. Bail-out quickly.235 return nullptr;236 }237 238 // Try to search a path from dynamic_type to dst_type.239 __dynamic_cast_info dynamic_to_dst_info = {dynamic_type,240 dst_ptr_to_static,241 dst_type,242 src2dst_offset,243 0,244 0,245 0,246 0,247 0,248 0,249 0,250 0,251 1, // number_of_dst_type252 false,253 false,254 false,255 true,256 nullptr};257 dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);258 if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {259 // We have found at least one path from dynamic_ptr to dst_ptr. The260 // downcast can succeed.261 return dst_ptr_to_static;262 }263 264 return nullptr;265}266 267const void* dyn_cast_slow(const void* static_ptr,268 const void* dynamic_ptr,269 const __class_type_info* static_type,270 const __class_type_info* dst_type,271 const __class_type_info* dynamic_type,272 std::ptrdiff_t src2dst_offset)273{274 // Not using giant short cut. Do the search275 276 // Initialize info struct for this search.277 __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,278 0, 0, 0, false, false, false, true, nullptr};279 280 dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);281#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST282 // The following if should always be false because we should283 // definitely find (static_ptr, static_type), either on a public284 // or private path285 if (info.path_dst_ptr_to_static_ptr == unknown &&286 info.path_dynamic_ptr_to_static_ptr == unknown)287 {288 static_assert(std::atomic<size_t>::is_always_lock_free, "");289 static std::atomic<size_t> error_count(0);290 size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);291 if ((error_count_snapshot & (error_count_snapshot-1)) == 0)292 syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "293 "has hidden visibility or is defined in more than one translation "294 "unit. They should all have public visibility. "295 "%s, %s, %s.\n", static_type->name(), dynamic_type->name(),296 dst_type->name());297 // Redo the search comparing type_info's using strcmp298 info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,299 0, 0, 0, false, false, false, true, nullptr};300 dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);301 }302#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST303 // Query the search.304 switch (info.number_to_static_ptr)305 {306 case 0:307 if (info.number_to_dst_ptr == 1 &&308 info.path_dynamic_ptr_to_static_ptr == public_path &&309 info.path_dynamic_ptr_to_dst_ptr == public_path)310 return info.dst_ptr_not_leading_to_static_ptr;311 break;312 case 1:313 if (info.path_dst_ptr_to_static_ptr == public_path ||314 (315 info.number_to_dst_ptr == 0 &&316 info.path_dynamic_ptr_to_static_ptr == public_path &&317 info.path_dynamic_ptr_to_dst_ptr == public_path318 )319 )320 return info.dst_ptr_leading_to_static_ptr;321 break;322 }323 324 return nullptr;325}326 327} // namespace328 329// __shim_type_info330 331__shim_type_info::~__shim_type_info()332{333}334 335void __shim_type_info::noop1() const {}336void __shim_type_info::noop2() const {}337 338// __fundamental_type_info339 340// This miraculously (compiler magic) emits the type_info's for:341// 1. all of the fundamental types342// 2. pointers to all of the fundamental types343// 3. pointers to all of the const fundamental types344__fundamental_type_info::~__fundamental_type_info()345{346}347 348// __array_type_info349 350__array_type_info::~__array_type_info()351{352}353 354// __function_type_info355 356__function_type_info::~__function_type_info()357{358}359 360// __enum_type_info361 362__enum_type_info::~__enum_type_info()363{364}365 366// __class_type_info367 368__class_type_info::~__class_type_info()369{370}371 372// __si_class_type_info373 374__si_class_type_info::~__si_class_type_info()375{376}377 378// __vmi_class_type_info379 380__vmi_class_type_info::~__vmi_class_type_info()381{382}383 384// __pbase_type_info385 386__pbase_type_info::~__pbase_type_info()387{388}389 390// __pointer_type_info391 392__pointer_type_info::~__pointer_type_info()393{394}395 396// __pointer_to_member_type_info397 398__pointer_to_member_type_info::~__pointer_to_member_type_info()399{400}401 402// can_catch403 404// A handler is a match for an exception object of type E if405// 1. The handler is of type cv T or cv T& and E and T are the same type406// (ignoring the top-level cv-qualifiers), or407// 2. the handler is of type cv T or cv T& and T is an unambiguous public408// base class of E, or409// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be410// converted to the type of the handler by either or both of411// A. a standard pointer conversion (4.10) not involving conversions to412// pointers to private or protected or ambiguous classes413// B. a qualification conversion414// 4. the handler is a pointer or pointer to member type and E is415// std::nullptr_t.416 417// adjustedPtr:418//419// catch (A& a) : adjustedPtr == &a420// catch (A* a) : adjustedPtr == a421// catch (A** a) : adjustedPtr == a422//423// catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object)424// catch (D2* d2) : adjustedPtr == d2425// catch (D2*& d2) : adjustedPtr == d2426//427// catch (...) : adjustedPtr == & of the exception428//429// If the thrown type is nullptr_t and the caught type is a pointer to430// member type, adjustedPtr points to a statically-allocated null pointer431// representation of that type.432 433// Handles bullet 1434bool435__fundamental_type_info::can_catch(const __shim_type_info* thrown_type,436 void*&) const437{438 return is_equal(this, thrown_type, false);439}440 441bool442__array_type_info::can_catch(const __shim_type_info*, void*&) const443{444 // We can get here if someone tries to catch an array by reference.445 // However if someone tries to throw an array, it immediately gets446 // converted to a pointer, which will not convert back to an array447 // at the catch clause. So this can never catch anything.448 return false;449}450 451bool452__function_type_info::can_catch(const __shim_type_info*, void*&) const453{454 // We can get here if someone tries to catch a function by reference.455 // However if someone tries to throw a function, it immediately gets456 // converted to a pointer, which will not convert back to a function457 // at the catch clause. So this can never catch anything.458 return false;459}460 461// Handles bullet 1462bool463__enum_type_info::can_catch(const __shim_type_info* thrown_type,464 void*&) const465{466 return is_equal(this, thrown_type, false);467}468 469#ifdef __clang__470#pragma clang diagnostic push471#pragma clang diagnostic ignored "-Wmissing-field-initializers"472#endif473 474// Handles bullets 1 and 2475bool476__class_type_info::can_catch(const __shim_type_info* thrown_type,477 void*& adjustedPtr) const478{479 // bullet 1480 if (is_equal(this, thrown_type, false))481 return true;482 const __class_type_info* thrown_class_type =483 dynamic_cast<const __class_type_info*>(thrown_type);484 if (thrown_class_type == 0)485 return false;486 // bullet 2487 _LIBCXXABI_ASSERT(adjustedPtr, "catching a class without an object?");488 __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true, nullptr};489 info.number_of_dst_type = 1;490 thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);491 if (info.path_dst_ptr_to_static_ptr == public_path)492 {493 adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);494 return true;495 }496 return false;497}498 499#ifdef __clang__500#pragma clang diagnostic pop501#endif502 503// When we have an object to inspect - we just pass the pointer to the sub-504// object that matched the static_type we just checked. If that is different505// from any previously recorded pointer to that object type, then we have506// an ambiguous case.507 508// When we have no object to inspect, we need to account for virtual bases509// explicitly.510// info->vbase_cookie is a pointer to the name of the innermost virtual base511// type, or nullptr if there is no virtual base on the path so far.512// adjustedPtr points to the subobject we just found.513// If vbase_cookie != any previously recorded (including the case of nullptr514// representing an already-found static sub-object) then we have an ambiguous515// case. Assuming that the vbase_cookie values agree; if then we have a516// different offset (adjustedPtr) from any previously recorded, this indicates517// an ambiguous case within the virtual base.518 519void520__class_type_info::process_found_base_class(__dynamic_cast_info* info,521 void* adjustedPtr,522 int path_below) const523{524 if (info->number_to_static_ptr == 0) {525 // First time we found this base526 info->dst_ptr_leading_to_static_ptr = adjustedPtr;527 info->path_dst_ptr_to_static_ptr = path_below;528 // stash the virtual base cookie.529 info->dst_ptr_not_leading_to_static_ptr = info->vbase_cookie;530 info->number_to_static_ptr = 1;531 } else if (info->dst_ptr_not_leading_to_static_ptr == info->vbase_cookie &&532 info->dst_ptr_leading_to_static_ptr == adjustedPtr) {533 // We've been here before. Update path to "most public"534 if (info->path_dst_ptr_to_static_ptr == not_public_path)535 info->path_dst_ptr_to_static_ptr = path_below;536 } else {537 // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)538 // to a static_type.539 info->number_to_static_ptr += 1;540 info->path_dst_ptr_to_static_ptr = not_public_path;541 info->search_done = true;542 }543}544 545void546__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,547 void* adjustedPtr,548 int path_below) const549{550 if (is_equal(this, info->static_type, false))551 process_found_base_class(info, adjustedPtr, path_below);552}553 554void555__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,556 void* adjustedPtr,557 int path_below) const558{559 if (is_equal(this, info->static_type, false))560 process_found_base_class(info, adjustedPtr, path_below);561 else562 __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below);563}564 565void566__base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,567 void* adjustedPtr,568 int path_below) const569{570 bool is_virtual = __offset_flags & __virtual_mask;571 ptrdiff_t offset_to_base = 0;572 if (info->have_object) {573 /* We have an object to inspect, we can look through its vtables to574 find the layout. */575 offset_to_base = __offset_flags >> __offset_shift;576 if (is_virtual) {577 const char* vtable = strip_vtable(*static_cast<const char* const*>(adjustedPtr));578 offset_to_base = update_offset_to_base(vtable, offset_to_base);579 }580 } else if (!is_virtual) {581 /* We have no object; however, for non-virtual bases, (since we do not582 need to inspect any content) we can pretend to have an object based583 at '0'. */584 offset_to_base = __offset_flags >> __offset_shift;585 } else {586 /* No object to inspect, and the next base is virtual.587 We cannot indirect through the vtable to find the actual object offset.588 So, update vbase_cookie to the new innermost virtual base using the589 pointer to the typeinfo name as a key. */590 info->vbase_cookie = static_cast<const void*>(__base_type->name());591 // .. and reset the pointer.592 adjustedPtr = nullptr;593 }594 __base_type->has_unambiguous_public_base(595 info, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(adjustedPtr) + offset_to_base),596 (__offset_flags & __public_mask) ? path_below : not_public_path);597}598 599void600__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,601 void* adjustedPtr,602 int path_below) const603{604 if (is_equal(this, info->static_type, false))605 process_found_base_class(info, adjustedPtr, path_below);606 else607 {608 typedef const __base_class_type_info* Iter;609 const Iter e = __base_info + __base_count;610 Iter p = __base_info;611 p->has_unambiguous_public_base(info, adjustedPtr, path_below);612 if (++p < e)613 {614 do615 {616 p->has_unambiguous_public_base(info, adjustedPtr, path_below);617 if (info->search_done)618 break;619 } while (++p < e);620 }621 }622}623 624// Handles bullet 1 for both pointers and member pointers625bool626__pbase_type_info::can_catch(const __shim_type_info* thrown_type,627 void*&) const628{629 bool use_strcmp = this->__flags & (__incomplete_class_mask |630 __incomplete_mask);631 if (!use_strcmp) {632 const __pbase_type_info* thrown_pbase = dynamic_cast<const __pbase_type_info*>(633 thrown_type);634 if (!thrown_pbase) return false;635 use_strcmp = thrown_pbase->__flags & (__incomplete_class_mask |636 __incomplete_mask);637 }638 return is_equal(this, thrown_type, use_strcmp);639}640 641#ifdef __clang__642#pragma clang diagnostic push643#pragma clang diagnostic ignored "-Wmissing-field-initializers"644#endif645 646// Handles bullets 1, 3 and 4647// NOTE: It might not be safe to adjust the pointer if it is not not a pointer648// type. Only adjust the pointer after we know it is safe to do so.649bool650__pointer_type_info::can_catch(const __shim_type_info* thrown_type,651 void*& adjustedPtr) const652{653 // bullet 4654 if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) {655 adjustedPtr = nullptr;656 return true;657 }658 659 // bullet 1660 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) {661 if (adjustedPtr != NULL)662 adjustedPtr = *static_cast<void**>(adjustedPtr);663 return true;664 }665 // bullet 3666 const __pointer_type_info* thrown_pointer_type =667 dynamic_cast<const __pointer_type_info*>(thrown_type);668 if (thrown_pointer_type == 0)669 return false;670 // Do the dereference adjustment671 if (adjustedPtr != NULL)672 adjustedPtr = *static_cast<void**>(adjustedPtr);673 // bullet 3B and 3C674 if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask)675 return false;676 if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask)677 return false;678 if (is_equal(__pointee, thrown_pointer_type->__pointee, false))679 return true;680 // bullet 3A681 if (is_equal(__pointee, &typeid(void), false)) {682 // pointers to functions cannot be converted to void*.683 // pointers to member functions are not handled here.684 const __function_type_info* thrown_function =685 dynamic_cast<const __function_type_info*>(thrown_pointer_type->__pointee);686 return (thrown_function == nullptr);687 }688 // Handle pointer to pointer689 const __pointer_type_info* nested_pointer_type =690 dynamic_cast<const __pointer_type_info*>(__pointee);691 if (nested_pointer_type) {692 if (~__flags & __const_mask) return false;693 return nested_pointer_type->can_catch_nested(thrown_pointer_type->__pointee);694 }695 696 // Handle pointer to pointer to member697 const __pointer_to_member_type_info* member_ptr_type =698 dynamic_cast<const __pointer_to_member_type_info*>(__pointee);699 if (member_ptr_type) {700 if (~__flags & __const_mask) return false;701 return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee);702 }703 704 // Handle pointer to class type705 const __class_type_info* catch_class_type =706 dynamic_cast<const __class_type_info*>(__pointee);707 if (catch_class_type == 0)708 return false;709 const __class_type_info* thrown_class_type =710 dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);711 if (thrown_class_type == 0)712 return false;713 bool have_object = adjustedPtr != nullptr;714 __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,715 have_object, nullptr};716 info.number_of_dst_type = 1;717 thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);718 if (info.path_dst_ptr_to_static_ptr == public_path)719 {720 // In the case of a thrown null pointer, we have no object but we might721 // well have computed the offset to where a public sub-object would be.722 // However, we do not want to return that offset to the user; we still723 // want them to catch a null ptr.724 if (have_object)725 adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);726 else727 adjustedPtr = nullptr;728 return true;729 }730 return false;731}732 733bool __pointer_type_info::can_catch_nested(734 const __shim_type_info* thrown_type) const735{736 const __pointer_type_info* thrown_pointer_type =737 dynamic_cast<const __pointer_type_info*>(thrown_type);738 if (thrown_pointer_type == 0)739 return false;740 // bullet 3B741 if (thrown_pointer_type->__flags & ~__flags)742 return false;743 if (is_equal(__pointee, thrown_pointer_type->__pointee, false))744 return true;745 // If the pointed to types differ then the catch type must be const746 // qualified.747 if (~__flags & __const_mask)748 return false;749 750 // Handle pointer to pointer751 const __pointer_type_info* nested_pointer_type =752 dynamic_cast<const __pointer_type_info*>(__pointee);753 if (nested_pointer_type) {754 return nested_pointer_type->can_catch_nested(755 thrown_pointer_type->__pointee);756 }757 758 // Handle pointer to pointer to member759 const __pointer_to_member_type_info* member_ptr_type =760 dynamic_cast<const __pointer_to_member_type_info*>(__pointee);761 if (member_ptr_type) {762 return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee);763 }764 765 return false;766}767 768bool __pointer_to_member_type_info::can_catch(769 const __shim_type_info* thrown_type, void*& adjustedPtr) const {770 // bullet 4771 if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) {772 // We assume that the pointer to member representation is the same for773 // all pointers to data members and for all pointers to member functions.774 struct X {};775 if (dynamic_cast<const __function_type_info*>(__pointee)) {776 static int (X::*const null_ptr_rep)() = nullptr;777 adjustedPtr = const_cast<int (X::**)()>(&null_ptr_rep);778 } else {779 static int X::*const null_ptr_rep = nullptr;780 adjustedPtr = const_cast<int X::**>(&null_ptr_rep);781 }782 return true;783 }784 785 // bullet 1786 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr))787 return true;788 789 const __pointer_to_member_type_info* thrown_pointer_type =790 dynamic_cast<const __pointer_to_member_type_info*>(thrown_type);791 if (thrown_pointer_type == 0)792 return false;793 if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask)794 return false;795 if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask)796 return false;797 if (!is_equal(__pointee, thrown_pointer_type->__pointee, false))798 return false;799 if (is_equal(__context, thrown_pointer_type->__context, false))800 return true;801 802 // [except.handle] does not allow the pointer-to-member conversions mentioned803 // in [mem.conv] to take place. For this reason we don't check Derived->Base804 // for Derived->Base conversions.805 806 return false;807}808 809bool __pointer_to_member_type_info::can_catch_nested(810 const __shim_type_info* thrown_type) const811{812 const __pointer_to_member_type_info* thrown_member_ptr_type =813 dynamic_cast<const __pointer_to_member_type_info*>(thrown_type);814 if (thrown_member_ptr_type == 0)815 return false;816 if (~__flags & thrown_member_ptr_type->__flags)817 return false;818 if (!is_equal(__pointee, thrown_member_ptr_type->__pointee, false))819 return false;820 if (!is_equal(__context, thrown_member_ptr_type->__context, false))821 return false;822 return true;823}824 825#ifdef __clang__826#pragma clang diagnostic pop827#endif828 829#ifdef __clang__830#pragma clang diagnostic push831#pragma clang diagnostic ignored "-Wmissing-field-initializers"832#endif833 834// __dynamic_cast835 836// static_ptr: pointer to an object of type static_type; nonnull, and since the837// object is polymorphic, *(void**)static_ptr is a virtual table pointer.838// static_ptr is &v in the expression dynamic_cast<T>(v).839// static_type: static type of the object pointed to by static_ptr.840// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)").841// src2dst_offset: a static hint about the location of the842// source subobject with respect to the complete object;843// special negative values are:844// -1: no hint845// -2: static_type is not a public base of dst_type846// -3: static_type is a multiple public base type but never a847// virtual base type848// otherwise, the static_type type is a unique public nonvirtual849// base type of dst_type at offset src2dst_offset from the850// origin of dst_type.851//852// (dynamic_ptr, dynamic_type) are the run time type of the complete object853// referred to by static_ptr and a pointer to it. These can be found from854// static_ptr for polymorphic types.855// static_type is guaranteed to be a polymorphic type.856//857// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each858// node of the tree represents a base class/object of its parent (or parents) below.859// Each node is uniquely represented by a pointer to the object, and a pointer860// to a type_info - its type. Different nodes may have the same pointer and861// different nodes may have the same type. But only one node has a specific862// (pointer-value, type) pair. In C++ two objects of the same type can not863// share the same address.864//865// There are two flavors of nodes which have the type dst_type:866// 1. Those that are derived from (below) (static_ptr, static_type).867// 2. Those that are not derived from (below) (static_ptr, static_type).868//869// Invariants of the DAG:870//871// There is at least one path from the root (dynamic_ptr, dynamic_type) to872// the node (static_ptr, static_type). This path may or may not be public.873// There may be more than one such path (some public some not). Such a path may874// or may not go through a node having type dst_type.875//876// No node of type T appears above a node of the same type. That means that877// there is only one node with dynamic_type. And if dynamic_type == dst_type,878// then there is only one dst_type in the DAG.879//880// No node of type dst_type appears above a node of type static_type. Such881// DAG's are possible in C++, but the compiler computes those dynamic_casts at882// compile time, and only calls __dynamic_cast when dst_type lies below883// static_type in the DAG.884//885// dst_type != static_type: The compiler computes the dynamic_cast in this case too.886// dynamic_type != static_type: The compiler computes the dynamic_cast in this case too.887//888// Returns:889//890// If there is exactly one dst_type of flavor 1, and891// If there is a public path from that dst_type to (static_ptr, static_type), or892// If there are 0 dst_types of flavor 2, and there is a public path from893// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public894// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return895// a pointer to that dst_type.896// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and897// if there is a public path from (dynamic_ptr, dynamic_type) to898// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)899// to the one dst_type, then return a pointer to that one dst_type.900// Else return nullptr.901//902// If dynamic_type == dst_type, then the above algorithm collapses to the903// following cheaper algorithm:904//905// If there is a public path from (dynamic_ptr, dynamic_type) to906// (static_ptr, static_type), then return dynamic_ptr.907// Else return nullptr.908 909extern "C" _LIBCXXABI_FUNC_VIS void *910__dynamic_cast(const void *static_ptr, const __class_type_info *static_type,911 const __class_type_info *dst_type,912 std::ptrdiff_t src2dst_offset) {913 // Get (dynamic_ptr, dynamic_type) from static_ptr914 derived_object_info derived_info;915 dyn_cast_get_derived_info(&derived_info, static_ptr);916 917 // Initialize answer to nullptr. This will be changed from the search918 // results if a non-null answer is found. Regardless, this is what will919 // be returned.920 const void* dst_ptr = 0;921 922 // Find out if we can use a giant short cut in the search923 if (is_equal(derived_info.dynamic_type, dst_type, false))924 {925 dst_ptr = dyn_cast_to_derived(static_ptr,926 derived_info.dynamic_ptr,927 static_type,928 dst_type,929 derived_info.offset_to_derived,930 src2dst_offset);931 }932 else933 {934 // Optimize toward downcasting: let's first try to do a downcast before935 // falling back to the slow path.936 dst_ptr = dyn_cast_try_downcast(static_ptr,937 derived_info.dynamic_ptr,938 dst_type,939 derived_info.dynamic_type,940 src2dst_offset);941 942 if (!dst_ptr)943 {944 dst_ptr = dyn_cast_slow(static_ptr,945 derived_info.dynamic_ptr,946 static_type,947 dst_type,948 derived_info.dynamic_type,949 src2dst_offset);950 }951 }952 953 return const_cast<void*>(dst_ptr);954}955 956#ifdef __clang__957#pragma clang diagnostic pop958#endif959 960// Call this function when you hit a static_type which is a base (above) a dst_type.961// Let caller know you hit a static_type. But only start recording details if962// this is (static_ptr, static_type) -- the node we are casting from.963// If this is (static_ptr, static_type)964// Record the path (public or not) from the dst_type to here. There may be965// multiple paths from the same dst_type to here, record the "most public" one.966// Record the dst_ptr as pointing to (static_ptr, static_type).967// If more than one (dst_ptr, dst_type) points to (static_ptr, static_type),968// then mark this dyanmic_cast as ambiguous and stop the search.969void970__class_type_info::process_static_type_above_dst(__dynamic_cast_info* info,971 const void* dst_ptr,972 const void* current_ptr,973 int path_below) const974{975 // Record that we found a static_type976 info->found_any_static_type = true;977 if (current_ptr == info->static_ptr)978 {979 // Record that we found (static_ptr, static_type)980 info->found_our_static_ptr = true;981 if (info->dst_ptr_leading_to_static_ptr == 0)982 {983 // First time here984 info->dst_ptr_leading_to_static_ptr = dst_ptr;985 info->path_dst_ptr_to_static_ptr = path_below;986 info->number_to_static_ptr = 1;987 // If there is only one dst_type in the entire tree and the path from988 // there to here is public then we are done!989 if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)990 info->search_done = true;991 }992 else if (info->dst_ptr_leading_to_static_ptr == dst_ptr)993 {994 // We've been here before. Update path to "most public"995 if (info->path_dst_ptr_to_static_ptr == not_public_path)996 info->path_dst_ptr_to_static_ptr = path_below;997 // If there is only one dst_type in the entire tree and the path from998 // there to here is public then we are done!999 if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)1000 info->search_done = true;1001 }1002 else1003 {1004 // We've detected an ambiguous cast from (static_ptr, static_type)1005 // to a dst_type1006 info->number_to_static_ptr += 1;1007 info->search_done = true;1008 }1009 }1010}1011 1012// Call this function when you hit a static_type which is not a base (above) a dst_type.1013// If this is (static_ptr, static_type)1014// Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be1015// multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one.1016void1017__class_type_info::process_static_type_below_dst(__dynamic_cast_info* info,1018 const void* current_ptr,1019 int path_below) const1020{1021 if (current_ptr == info->static_ptr)1022 {1023 // Record the most public path from (dynamic_ptr, dynamic_type) to1024 // (static_ptr, static_type)1025 if (info->path_dynamic_ptr_to_static_ptr != public_path)1026 info->path_dynamic_ptr_to_static_ptr = path_below;1027 }1028}1029 1030// Call this function when searching below a dst_type node. This function searches1031// for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes.1032// If it finds a static_type node, there is no need to further search base classes1033// above.1034// If it finds a dst_type node it should search base classes using search_above_dst1035// to find out if this dst_type points to (static_ptr, static_type) or not.1036// Either way, the dst_type is recorded as one of two "flavors": one that does1037// or does not point to (static_ptr, static_type).1038// If this is neither a static_type nor a dst_type node, continue searching1039// base classes above.1040// All the hoopla surrounding the search code is doing nothing but looking for1041// excuses to stop the search prematurely (break out of the for-loop). That is,1042// the algorithm below is simply an optimization of this:1043// void1044// __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,1045// const void* current_ptr,1046// int path_below) const1047// {1048// typedef const __base_class_type_info* Iter;1049// if (this == info->static_type)1050// process_static_type_below_dst(info, current_ptr, path_below);1051// else if (this == info->dst_type)1052// {1053// // Record the most public access path that got us here1054// if (info->path_dynamic_ptr_to_dst_ptr != public_path)1055// info->path_dynamic_ptr_to_dst_ptr = path_below;1056// bool does_dst_type_point_to_our_static_type = false;1057// for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p)1058// {1059// p->search_above_dst(info, current_ptr, current_ptr, public_path);1060// if (info->found_our_static_ptr)1061// does_dst_type_point_to_our_static_type = true;1062// // break out early here if you can detect it doesn't matter if you do1063// }1064// if (!does_dst_type_point_to_our_static_type)1065// {1066// // We found a dst_type that doesn't point to (static_ptr, static_type)1067// // So record the address of this dst_ptr and increment the1068// // count of the number of such dst_types found in the tree.1069// info->dst_ptr_not_leading_to_static_ptr = current_ptr;1070// info->number_to_dst_ptr += 1;1071// }1072// }1073// else1074// {1075// // This is not a static_type and not a dst_type.1076// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)1077// {1078// p->search_below_dst(info, current_ptr, public_path);1079// // break out early here if you can detect it doesn't matter if you do1080// }1081// }1082// }1083void1084__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,1085 const void* current_ptr,1086 int path_below,1087 bool use_strcmp) const1088{1089 typedef const __base_class_type_info* Iter;1090 if (is_equal(this, info->static_type, use_strcmp))1091 process_static_type_below_dst(info, current_ptr, path_below);1092 else if (is_equal(this, info->dst_type, use_strcmp))1093 {1094 // We've been here before if we've recorded current_ptr in one of these1095 // two places:1096 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||1097 current_ptr == info->dst_ptr_not_leading_to_static_ptr)1098 {1099 // We've seen this node before, and therefore have already searched1100 // its base classes above.1101 // Update path to here that is "most public".1102 if (path_below == public_path)1103 info->path_dynamic_ptr_to_dst_ptr = public_path;1104 }1105 else // We have haven't been here before1106 {1107 // Record the access path that got us here1108 // If there is more than one dst_type this path doesn't matter.1109 info->path_dynamic_ptr_to_dst_ptr = path_below;1110 bool does_dst_type_point_to_our_static_type = false;1111 // Only search above here if dst_type derives from static_type, or1112 // if it is unknown if dst_type derives from static_type.1113 if (info->is_dst_type_derived_from_static_type != no)1114 {1115 // Set up flags to record results from all base classes1116 bool is_dst_type_derived_from_static_type = false;1117 1118 // We've found a dst_type with a potentially public path to here.1119 // We have to assume the path is public because it may become1120 // public later (if we get back to here with a public path).1121 // We can stop looking above if:1122 // 1. We've found a public path to (static_ptr, static_type).1123 // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.1124 // This is detected at the (static_ptr, static_type).1125 // 3. We can prove that there is no public path to (static_ptr, static_type)1126 // above here.1127 const Iter e = __base_info + __base_count;1128 for (Iter p = __base_info; p < e; ++p)1129 {1130 // Zero out found flags1131 info->found_our_static_ptr = false;1132 info->found_any_static_type = false;1133 p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);1134 if (info->search_done)1135 break;1136 if (info->found_any_static_type)1137 {1138 is_dst_type_derived_from_static_type = true;1139 if (info->found_our_static_ptr)1140 {1141 does_dst_type_point_to_our_static_type = true;1142 // If we found what we're looking for, stop looking above.1143 if (info->path_dst_ptr_to_static_ptr == public_path)1144 break;1145 // We found a private path to (static_ptr, static_type)1146 // If there is no diamond then there is only one path1147 // to (static_ptr, static_type) and we just found it.1148 if (!(__flags & __diamond_shaped_mask))1149 break;1150 }1151 else1152 {1153 // If we found a static_type that isn't the one we're looking1154 // for, and if there are no repeated types above here,1155 // then stop looking.1156 if (!(__flags & __non_diamond_repeat_mask))1157 break;1158 }1159 }1160 }1161 // If we found no static_type,s then dst_type doesn't derive1162 // from static_type, else it does. Record this result so that1163 // next time we hit a dst_type we will know not to search above1164 // it if it doesn't derive from static_type.1165 if (is_dst_type_derived_from_static_type)1166 info->is_dst_type_derived_from_static_type = yes;1167 else1168 info->is_dst_type_derived_from_static_type = no;1169 }1170 if (!does_dst_type_point_to_our_static_type)1171 {1172 // We found a dst_type that doesn't point to (static_ptr, static_type)1173 // So record the address of this dst_ptr and increment the1174 // count of the number of such dst_types found in the tree.1175 info->dst_ptr_not_leading_to_static_ptr = current_ptr;1176 info->number_to_dst_ptr += 1;1177 // If there exists another dst with a private path to1178 // (static_ptr, static_type), then the cast from1179 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous,1180 // so stop search.1181 if (info->number_to_static_ptr == 1 &&1182 info->path_dst_ptr_to_static_ptr == not_public_path)1183 info->search_done = true;1184 }1185 }1186 }1187 else1188 {1189 // This is not a static_type and not a dst_type.1190 const Iter e = __base_info + __base_count;1191 Iter p = __base_info;1192 p->search_below_dst(info, current_ptr, path_below, use_strcmp);1193 if (++p < e)1194 {1195 if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)1196 {1197 // If there are multiple paths to a base above from here, or if1198 // a dst_type pointing to (static_ptr, static_type) has been found,1199 // then there is no way to break out of this loop early unless1200 // something below detects the search is done.1201 do1202 {1203 if (info->search_done)1204 break;1205 p->search_below_dst(info, current_ptr, path_below, use_strcmp);1206 } while (++p < e);1207 }1208 else if (__flags & __non_diamond_repeat_mask)1209 {1210 // There are not multiple paths to any base class from here and a1211 // dst_type pointing to (static_ptr, static_type) has not yet been1212 // found.1213 do1214 {1215 if (info->search_done)1216 break;1217 // If we just found a dst_type with a public path to (static_ptr, static_type),1218 // then the only reason to continue the search is to make sure1219 // no other dst_type points to (static_ptr, static_type).1220 // If !diamond, then we don't need to search here.1221 if (info->number_to_static_ptr == 1 &&1222 info->path_dst_ptr_to_static_ptr == public_path)1223 break;1224 p->search_below_dst(info, current_ptr, path_below, use_strcmp);1225 } while (++p < e);1226 }1227 else1228 {1229 // There are no repeated types above this node.1230 // There are no nodes with multiple parents above this node.1231 // no dst_type has been found to (static_ptr, static_type)1232 do1233 {1234 if (info->search_done)1235 break;1236 // If we just found a dst_type with a public path to (static_ptr, static_type),1237 // then the only reason to continue the search is to make sure1238 // no other dst_type points to (static_ptr, static_type).1239 // If !diamond, then we don't need to search here.1240 // if we just found a dst_type with a private path to (static_ptr, static_type),1241 // then we're only looking for a public path to (static_ptr, static_type)1242 // and to check for other dst_types.1243 // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type)1244 // and not a dst_type under here.1245 if (info->number_to_static_ptr == 1)1246 break;1247 p->search_below_dst(info, current_ptr, path_below, use_strcmp);1248 } while (++p < e);1249 }1250 }1251 }1252}1253 1254// This is the same algorithm as __vmi_class_type_info::search_below_dst but1255// simplified to the case that there is only a single base class.1256void1257__si_class_type_info::search_below_dst(__dynamic_cast_info* info,1258 const void* current_ptr,1259 int path_below,1260 bool use_strcmp) const1261{1262 if (is_equal(this, info->static_type, use_strcmp))1263 process_static_type_below_dst(info, current_ptr, path_below);1264 else if (is_equal(this, info->dst_type, use_strcmp))1265 {1266 // We've been here before if we've recorded current_ptr in one of these1267 // two places:1268 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||1269 current_ptr == info->dst_ptr_not_leading_to_static_ptr)1270 {1271 // We've seen this node before, and therefore have already searched1272 // its base classes above.1273 // Update path to here that is "most public".1274 if (path_below == public_path)1275 info->path_dynamic_ptr_to_dst_ptr = public_path;1276 }1277 else // We have haven't been here before1278 {1279 // Record the access path that got us here1280 // If there is more than one dst_type this path doesn't matter.1281 info->path_dynamic_ptr_to_dst_ptr = path_below;1282 bool does_dst_type_point_to_our_static_type = false;1283 // Only search above here if dst_type derives from static_type, or1284 // if it is unknown if dst_type derives from static_type.1285 if (info->is_dst_type_derived_from_static_type != no)1286 {1287 // Set up flags to record results from all base classes1288 bool is_dst_type_derived_from_static_type = false;1289 // Zero out found flags1290 info->found_our_static_ptr = false;1291 info->found_any_static_type = false;1292 __base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);1293 if (info->found_any_static_type)1294 {1295 is_dst_type_derived_from_static_type = true;1296 if (info->found_our_static_ptr)1297 does_dst_type_point_to_our_static_type = true;1298 }1299 // If we found no static_type,s then dst_type doesn't derive1300 // from static_type, else it does. Record this result so that1301 // next time we hit a dst_type we will know not to search above1302 // it if it doesn't derive from static_type.1303 if (is_dst_type_derived_from_static_type)1304 info->is_dst_type_derived_from_static_type = yes;1305 else1306 info->is_dst_type_derived_from_static_type = no;1307 }1308 if (!does_dst_type_point_to_our_static_type)1309 {1310 // We found a dst_type that doesn't point to (static_ptr, static_type)1311 // So record the address of this dst_ptr and increment the1312 // count of the number of such dst_types found in the tree.1313 info->dst_ptr_not_leading_to_static_ptr = current_ptr;1314 info->number_to_dst_ptr += 1;1315 // If there exists another dst with a private path to1316 // (static_ptr, static_type), then the cast from1317 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.1318 if (info->number_to_static_ptr == 1 &&1319 info->path_dst_ptr_to_static_ptr == not_public_path)1320 info->search_done = true;1321 }1322 }1323 }1324 else1325 {1326 // This is not a static_type and not a dst_type1327 __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp);1328 }1329}1330 1331// This is the same algorithm as __vmi_class_type_info::search_below_dst but1332// simplified to the case that there is no base class.1333void1334__class_type_info::search_below_dst(__dynamic_cast_info* info,1335 const void* current_ptr,1336 int path_below,1337 bool use_strcmp) const1338{1339 if (is_equal(this, info->static_type, use_strcmp))1340 process_static_type_below_dst(info, current_ptr, path_below);1341 else if (is_equal(this, info->dst_type, use_strcmp))1342 {1343 // We've been here before if we've recorded current_ptr in one of these1344 // two places:1345 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||1346 current_ptr == info->dst_ptr_not_leading_to_static_ptr)1347 {1348 // We've seen this node before, and therefore have already searched1349 // its base classes above.1350 // Update path to here that is "most public".1351 if (path_below == public_path)1352 info->path_dynamic_ptr_to_dst_ptr = public_path;1353 }1354 else // We have haven't been here before1355 {1356 // Record the access path that got us here1357 // If there is more than one dst_type this path doesn't matter.1358 info->path_dynamic_ptr_to_dst_ptr = path_below;1359 // We found a dst_type that doesn't point to (static_ptr, static_type)1360 // So record the address of this dst_ptr and increment the1361 // count of the number of such dst_types found in the tree.1362 info->dst_ptr_not_leading_to_static_ptr = current_ptr;1363 info->number_to_dst_ptr += 1;1364 // If there exists another dst with a private path to1365 // (static_ptr, static_type), then the cast from1366 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.1367 if (info->number_to_static_ptr == 1 &&1368 info->path_dst_ptr_to_static_ptr == not_public_path)1369 info->search_done = true;1370 // We found that dst_type does not derive from static_type1371 info->is_dst_type_derived_from_static_type = no;1372 }1373 }1374}1375 1376// Call this function when searching above a dst_type node. This function searches1377// for a public path to (static_ptr, static_type).1378// This function is guaranteed not to find a node of type dst_type.1379// Theoretically this is a very simple function which just stops if it finds a1380// static_type node: All the hoopla surrounding the search code is doing1381// nothing but looking for excuses to stop the search prematurely (break out of1382// the for-loop). That is, the algorithm below is simply an optimization of this:1383// void1384// __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,1385// const void* dst_ptr,1386// const void* current_ptr,1387// int path_below) const1388// {1389// if (this == info->static_type)1390// process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);1391// else1392// {1393// typedef const __base_class_type_info* Iter;1394// // This is not a static_type and not a dst_type1395// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)1396// {1397// p->search_above_dst(info, dst_ptr, current_ptr, public_path);1398// // break out early here if you can detect it doesn't matter if you do1399// }1400// }1401// }1402void1403__vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,1404 const void* dst_ptr,1405 const void* current_ptr,1406 int path_below,1407 bool use_strcmp) const1408{1409 if (is_equal(this, info->static_type, use_strcmp))1410 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);1411 else1412 {1413 typedef const __base_class_type_info* Iter;1414 // This is not a static_type and not a dst_type1415 // Save flags so they can be restored when returning to nodes below.1416 bool found_our_static_ptr = info->found_our_static_ptr;1417 bool found_any_static_type = info->found_any_static_type;1418 // We've found a dst_type below with a path to here. If the path1419 // to here is not public, there may be another path to here that1420 // is public. So we have to assume that the path to here is public.1421 // We can stop looking above if:1422 // 1. We've found a public path to (static_ptr, static_type).1423 // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.1424 // This is detected at the (static_ptr, static_type).1425 // 3. We can prove that there is no public path to (static_ptr, static_type)1426 // above here.1427 const Iter e = __base_info + __base_count;1428 Iter p = __base_info;1429 // Zero out found flags1430 info->found_our_static_ptr = false;1431 info->found_any_static_type = false;1432 p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);1433 found_our_static_ptr |= info->found_our_static_ptr;1434 found_any_static_type |= info->found_any_static_type;1435 if (++p < e)1436 {1437 do1438 {1439 if (info->search_done)1440 break;1441 if (info->found_our_static_ptr)1442 {1443 // If we found what we're looking for, stop looking above.1444 if (info->path_dst_ptr_to_static_ptr == public_path)1445 break;1446 // We found a private path to (static_ptr, static_type)1447 // If there is no diamond then there is only one path1448 // to (static_ptr, static_type) from here and we just found it.1449 if (!(__flags & __diamond_shaped_mask))1450 break;1451 }1452 else if (info->found_any_static_type)1453 {1454 // If we found a static_type that isn't the one we're looking1455 // for, and if there are no repeated types above here,1456 // then stop looking.1457 if (!(__flags & __non_diamond_repeat_mask))1458 break;1459 }1460 // Zero out found flags1461 info->found_our_static_ptr = false;1462 info->found_any_static_type = false;1463 p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);1464 found_our_static_ptr |= info->found_our_static_ptr;1465 found_any_static_type |= info->found_any_static_type;1466 } while (++p < e);1467 }1468 // Restore flags1469 info->found_our_static_ptr = found_our_static_ptr;1470 info->found_any_static_type = found_any_static_type;1471 }1472}1473 1474// This is the same algorithm as __vmi_class_type_info::search_above_dst but1475// simplified to the case that there is only a single base class.1476void1477__si_class_type_info::search_above_dst(__dynamic_cast_info* info,1478 const void* dst_ptr,1479 const void* current_ptr,1480 int path_below,1481 bool use_strcmp) const1482{1483 if (is_equal(this, info->static_type, use_strcmp))1484 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);1485 else1486 __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);1487}1488 1489// This is the same algorithm as __vmi_class_type_info::search_above_dst but1490// simplified to the case that there is no base class.1491void1492__class_type_info::search_above_dst(__dynamic_cast_info* info,1493 const void* dst_ptr,1494 const void* current_ptr,1495 int path_below,1496 bool use_strcmp) const1497{1498 if (is_equal(this, info->static_type, use_strcmp))1499 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);1500}1501 1502// The search functions for __base_class_type_info are simply convenience1503// functions for adjusting the current_ptr and path_below as the search is1504// passed up to the base class node.1505 1506void1507__base_class_type_info::search_above_dst(__dynamic_cast_info* info,1508 const void* dst_ptr,1509 const void* current_ptr,1510 int path_below,1511 bool use_strcmp) const1512{1513 ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;1514 if (__offset_flags & __virtual_mask)1515 {1516 const char* vtable = strip_vtable(*static_cast<const char* const*>(current_ptr));1517 offset_to_base = update_offset_to_base(vtable, offset_to_base);1518 }1519 __base_type->search_above_dst(info, dst_ptr,1520 static_cast<const char*>(current_ptr) + offset_to_base,1521 (__offset_flags & __public_mask) ?1522 path_below :1523 not_public_path,1524 use_strcmp);1525}1526 1527void1528__base_class_type_info::search_below_dst(__dynamic_cast_info* info,1529 const void* current_ptr,1530 int path_below,1531 bool use_strcmp) const1532{1533 ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;1534 if (__offset_flags & __virtual_mask)1535 {1536 const char* vtable = strip_vtable(*static_cast<const char* const*>(current_ptr));1537 offset_to_base = update_offset_to_base(vtable, offset_to_base);1538 }1539 __base_type->search_below_dst(info,1540 static_cast<const char*>(current_ptr) + offset_to_base,1541 (__offset_flags & __public_mask) ?1542 path_below :1543 not_public_path,1544 use_strcmp);1545}1546 1547} // __cxxabiv11548