1//===----------------------- private_typeinfo.cpp -------------------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "private_typeinfo.h"
10
11// The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more
12// forgiving when type_info's mistakenly have hidden visibility and thus
13// multiple type_infos can exist for a single type.
14//
15// When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where
16// there is a detected inconsistency in the type_info hierarchy during a
17// dynamic_cast, then the equality operation will fall back to using strcmp
18// on type_info names to determine type_info equality.
19//
20// This change happens *only* under dynamic_cast, and only when
21// dynamic_cast is faced with the choice: abort, or possibly give back the
22// wrong answer. If when the dynamic_cast is done with this fallback
23// algorithm and an inconsistency is still detected, dynamic_cast will call
24// abort with an appropriate message.
25//
26// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a
27// 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// _LIBCXX_DYNAMIC_FALLBACK is currently off by default.
35
36// On Windows, typeids are different between DLLs and EXEs, so comparing
37// type_info* will work for typeids from the same compiled file but fail
38// for typeids from a DLL and an executable. Among other things, exceptions
39// are not caught by handlers since can_catch() returns false.
40//
41// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls
42// is_equal() with use_strcmp=false so the string names are not compared.
43
44#include <string.h>
45
46#ifdef _LIBCXX_DYNAMIC_FALLBACK
47#include "abort_message.h"
48#include <sys/syslog.h>
49#endif
50
51static inline
52bool
53is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp)
54{
55 // Use std::type_info's default comparison unless we've explicitly asked
56 // for strcmp.
57 if (!use_strcmp)
58 return *x == *y;
59 // Still allow pointer equality to short circut.
60 return x == y || strcmp(x->name(), y->name()) == 0;
61}
62
63namespace __cxxabiv1
64{
65
66// __shim_type_info
67
68__shim_type_info::~__shim_type_info()
69{
70}
71
72void __shim_type_info::noop1() const {}
73void __shim_type_info::noop2() const {}
74
75// __fundamental_type_info
76
77// This miraculously (compiler magic) emits the type_info's for:
78// 1. all of the fundamental types
79// 2. pointers to all of the fundamental types
80// 3. pointers to all of the const fundamental types
81__fundamental_type_info::~__fundamental_type_info()
82{
83}
84
85// __array_type_info
86
87__array_type_info::~__array_type_info()
88{
89}
90
91// __function_type_info
92
93__function_type_info::~__function_type_info()
94{
95}
96
97// __enum_type_info
98
99__enum_type_info::~__enum_type_info()
100{
101}
102
103// __class_type_info
104
105__class_type_info::~__class_type_info()
106{
107}
108
109// __si_class_type_info
110
111__si_class_type_info::~__si_class_type_info()
112{
113}
114
115// __vmi_class_type_info
116
117__vmi_class_type_info::~__vmi_class_type_info()
118{
119}
120
121// __pbase_type_info
122
123__pbase_type_info::~__pbase_type_info()
124{
125}
126
127// __pointer_type_info
128
129__pointer_type_info::~__pointer_type_info()
130{
131}
132
133// __pointer_to_member_type_info
134
135__pointer_to_member_type_info::~__pointer_to_member_type_info()
136{
137}
138
139// can_catch
140
141// A handler is a match for an exception object of type E if
142// 1. The handler is of type cv T or cv T& and E and T are the same type
143// (ignoring the top-level cv-qualifiers), or
144// 2. the handler is of type cv T or cv T& and T is an unambiguous public
145// base class of E, or
146// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be
147// converted to the type of the handler by either or both of
148// A. a standard pointer conversion (4.10) not involving conversions to
149// pointers to private or protected or ambiguous classes
150// B. a qualification conversion
151// 4. the handler is a pointer or pointer to member type and E is
152// std::nullptr_t.
153
154// adjustedPtr:
155//
156// catch (A& a) : adjustedPtr == &a
157// catch (A* a) : adjustedPtr == a
158// catch (A** a) : adjustedPtr == a
159//
160// catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object)
161// catch (D2* d2) : adjustedPtr == d2
162// catch (D2*& d2) : adjustedPtr == d2
163//
164// catch (...) : adjustedPtr == & of the exception
165//
166// If the thrown type is nullptr_t and the caught type is a pointer to
167// member type, adjustedPtr points to a statically-allocated null pointer
168// representation of that type.
169
170// Handles bullet 1
171bool
172__fundamental_type_info::can_catch(const __shim_type_info* thrown_type,
173 void*&) const
174{
175 return is_equal(this, thrown_type, false);
176}
177
178bool
179__array_type_info::can_catch(const __shim_type_info*, void*&) const
180{
181 // We can get here if someone tries to catch an array by reference.
182 // However if someone tries to throw an array, it immediately gets
183 // converted to a pointer, which will not convert back to an array
184 // at the catch clause. So this can never catch anything.
185 return false;
186}
187
188bool
189__function_type_info::can_catch(const __shim_type_info*, void*&) const
190{
191 // We can get here if someone tries to catch a function by reference.
192 // However if someone tries to throw a function, it immediately gets
193 // converted to a pointer, which will not convert back to a function
194 // at the catch clause. So this can never catch anything.
195 return false;
196}
197
198// Handles bullet 1
199bool
200__enum_type_info::can_catch(const __shim_type_info* thrown_type,
201 void*&) const
202{
203 return is_equal(this, thrown_type, false);
204}
205
206#ifdef __clang__
207#pragma clang diagnostic push
208#pragma clang diagnostic ignored "-Wmissing-field-initializers"
209#endif
210
211// Handles bullets 1 and 2
212bool
213__class_type_info::can_catch(const __shim_type_info* thrown_type,
214 void*& adjustedPtr) const
215{
216 // bullet 1
217 if (is_equal(this, thrown_type, false))
218 return true;
219 const __class_type_info* thrown_class_type =
220 dynamic_cast<const __class_type_info*>(thrown_type);
221 if (thrown_class_type == 0)
222 return false;
223 // bullet 2
224 __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
225 info.number_of_dst_type = 1;
226 thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
227 if (info.path_dst_ptr_to_static_ptr == public_path)
228 {
229 adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
230 return true;
231 }
232 return false;
233}
234
235#ifdef __clang__
236#pragma clang diagnostic pop
237#endif
238
239void
240__class_type_info::process_found_base_class(__dynamic_cast_info* info,
241 void* adjustedPtr,
242 int path_below) const
243{
244 if (info->dst_ptr_leading_to_static_ptr == 0)
245 {
246 // First time here
247 info->dst_ptr_leading_to_static_ptr = adjustedPtr;
248 info->path_dst_ptr_to_static_ptr = path_below;
249 info->number_to_static_ptr = 1;
250 }
251 else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr)
252 {
253 // We've been here before. Update path to "most public"
254 if (info->path_dst_ptr_to_static_ptr == not_public_path)
255 info->path_dst_ptr_to_static_ptr = path_below;
256 }
257 else
258 {
259 // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
260 // to a static_type
261 info->number_to_static_ptr += 1;
262 info->path_dst_ptr_to_static_ptr = not_public_path;
263 info->search_done = true;
264 }
265}
266
267void
268__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
269 void* adjustedPtr,
270 int path_below) const
271{
272 if (is_equal(this, info->static_type, false))
273 process_found_base_class(info, adjustedPtr, path_below);
274}
275
276void
277__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
278 void* adjustedPtr,
279 int path_below) const
280{
281 if (is_equal(this, info->static_type, false))
282 process_found_base_class(info, adjustedPtr, path_below);
283 else
284 __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below);
285}
286
287void
288__base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
289 void* adjustedPtr,
290 int path_below) const
291{
292 ptrdiff_t offset_to_base = 0;
293 if (adjustedPtr != nullptr)
294 {
295 offset_to_base = __offset_flags >> __offset_shift;
296 if (__offset_flags & __virtual_mask)
297 {
298 const char* vtable = *static_cast<const char*const*>(adjustedPtr);
299 offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
300 }
301 }
302 __base_type->has_unambiguous_public_base(
303 info,
304 static_cast<char*>(adjustedPtr) + offset_to_base,
305 (__offset_flags & __public_mask) ? path_below : not_public_path);
306}
307
308void
309__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
310 void* adjustedPtr,
311 int path_below) const
312{
313 if (is_equal(this, info->static_type, false))
314 process_found_base_class(info, adjustedPtr, path_below);
315 else
316 {
317 typedef const __base_class_type_info* Iter;
318 const Iter e = __base_info + __base_count;
319 Iter p = __base_info;
320 p->has_unambiguous_public_base(info, adjustedPtr, path_below);
321 if (++p < e)
322 {
323 do
324 {
325 p->has_unambiguous_public_base(info, adjustedPtr, path_below);
326 if (info->search_done)
327 break;
328 } while (++p < e);
329 }
330 }
331}
332
333// Handles bullet 1 for both pointers and member pointers
334bool
335__pbase_type_info::can_catch(const __shim_type_info* thrown_type,
336 void*&) const
337{
338 bool use_strcmp = this->__flags & (__incomplete_class_mask |
339 __incomplete_mask);
340 if (!use_strcmp) {
341 const __pbase_type_info* thrown_pbase = dynamic_cast<const __pbase_type_info*>(
342 thrown_type);
343 if (!thrown_pbase) return false;
344 use_strcmp = thrown_pbase->__flags & (__incomplete_class_mask |
345 __incomplete_mask);
346 }
347 return is_equal(this, thrown_type, use_strcmp);
348}
349
350#ifdef __clang__
351#pragma clang diagnostic push
352#pragma clang diagnostic ignored "-Wmissing-field-initializers"
353#endif
354
355// Handles bullets 1, 3 and 4
356// NOTE: It might not be safe to adjust the pointer if it is not not a pointer
357// type. Only adjust the pointer after we know it is safe to do so.
358bool
359__pointer_type_info::can_catch(const __shim_type_info* thrown_type,
360 void*& adjustedPtr) const
361{
362 // bullet 4
363 if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) {
364 adjustedPtr = nullptr;
365 return true;
366 }
367
368 // bullet 1
369 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) {
370 if (adjustedPtr != NULL)
371 adjustedPtr = *static_cast<void**>(adjustedPtr);
372 return true;
373 }
374 // bullet 3
375 const __pointer_type_info* thrown_pointer_type =
376 dynamic_cast<const __pointer_type_info*>(thrown_type);
377 if (thrown_pointer_type == 0)
378 return false;
379 // Do the dereference adjustment
380 if (adjustedPtr != NULL)
381 adjustedPtr = *static_cast<void**>(adjustedPtr);
382 // bullet 3B and 3C
383 if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask)
384 return false;
385 if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask)
386 return false;
387 if (is_equal(__pointee, thrown_pointer_type->__pointee, false))
388 return true;
389 // bullet 3A
390 if (is_equal(__pointee, &typeid(void), false)) {
391 // pointers to functions cannot be converted to void*.
392 // pointers to member functions are not handled here.
393 const __function_type_info* thrown_function =
394 dynamic_cast<const __function_type_info*>(thrown_pointer_type->__pointee);
395 return (thrown_function == nullptr);
396 }
397 // Handle pointer to pointer
398 const __pointer_type_info* nested_pointer_type =
399 dynamic_cast<const __pointer_type_info*>(__pointee);
400 if (nested_pointer_type) {
401 if (~__flags & __const_mask) return false;
402 return nested_pointer_type->can_catch_nested(thrown_pointer_type->__pointee);
403 }
404
405 // Handle pointer to pointer to member
406 const __pointer_to_member_type_info* member_ptr_type =
407 dynamic_cast<const __pointer_to_member_type_info*>(__pointee);
408 if (member_ptr_type) {
409 if (~__flags & __const_mask) return false;
410 return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee);
411 }
412
413 // Handle pointer to class type
414 const __class_type_info* catch_class_type =
415 dynamic_cast<const __class_type_info*>(__pointee);
416 if (catch_class_type == 0)
417 return false;
418 const __class_type_info* thrown_class_type =
419 dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);
420 if (thrown_class_type == 0)
421 return false;
422 __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
423 info.number_of_dst_type = 1;
424 thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
425 if (info.path_dst_ptr_to_static_ptr == public_path)
426 {
427 if (adjustedPtr != NULL)
428 adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
429 return true;
430 }
431 return false;
432}
433
434bool __pointer_type_info::can_catch_nested(
435 const __shim_type_info* thrown_type) const
436{
437 const __pointer_type_info* thrown_pointer_type =
438 dynamic_cast<const __pointer_type_info*>(thrown_type);
439 if (thrown_pointer_type == 0)
440 return false;
441 // bullet 3B
442 if (thrown_pointer_type->__flags & ~__flags)
443 return false;
444 if (is_equal(__pointee, thrown_pointer_type->__pointee, false))
445 return true;
446 // If the pointed to types differ then the catch type must be const
447 // qualified.
448 if (~__flags & __const_mask)
449 return false;
450
451 // Handle pointer to pointer
452 const __pointer_type_info* nested_pointer_type =
453 dynamic_cast<const __pointer_type_info*>(__pointee);
454 if (nested_pointer_type) {
455 return nested_pointer_type->can_catch_nested(
456 thrown_pointer_type->__pointee);
457 }
458
459 // Handle pointer to pointer to member
460 const __pointer_to_member_type_info* member_ptr_type =
461 dynamic_cast<const __pointer_to_member_type_info*>(__pointee);
462 if (member_ptr_type) {
463 return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee);
464 }
465
466 return false;
467}
468
469bool __pointer_to_member_type_info::can_catch(
470 const __shim_type_info* thrown_type, void*& adjustedPtr) const {
471 // bullet 4
472 if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) {
473 // We assume that the pointer to member representation is the same for
474 // all pointers to data members and for all pointers to member functions.
475 struct X {};
476 if (dynamic_cast<const __function_type_info*>(__pointee)) {
477 static int (X::*const null_ptr_rep)() = nullptr;
478 adjustedPtr = const_cast<int (X::**)()>(&null_ptr_rep);
479 } else {
480 static int X::*const null_ptr_rep = nullptr;
481 adjustedPtr = const_cast<int X::**>(&null_ptr_rep);
482 }
483 return true;
484 }
485
486 // bullet 1
487 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr))
488 return true;
489
490 const __pointer_to_member_type_info* thrown_pointer_type =
491 dynamic_cast<const __pointer_to_member_type_info*>(thrown_type);
492 if (thrown_pointer_type == 0)
493 return false;
494 if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask)
495 return false;
496 if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask)
497 return false;
498 if (!is_equal(__pointee, thrown_pointer_type->__pointee, false))
499 return false;
500 if (is_equal(__context, thrown_pointer_type->__context, false))
501 return true;
502
503 // [except.handle] does not allow the pointer-to-member conversions mentioned
504 // in [mem.conv] to take place. For this reason we don't check Derived->Base
505 // for Derived->Base conversions.
506
507 return false;
508}
509
510bool __pointer_to_member_type_info::can_catch_nested(
511 const __shim_type_info* thrown_type) const
512{
513 const __pointer_to_member_type_info* thrown_member_ptr_type =
514 dynamic_cast<const __pointer_to_member_type_info*>(thrown_type);
515 if (thrown_member_ptr_type == 0)
516 return false;
517 if (~__flags & thrown_member_ptr_type->__flags)
518 return false;
519 if (!is_equal(__pointee, thrown_member_ptr_type->__pointee, false))
520 return false;
521 if (!is_equal(__context, thrown_member_ptr_type->__context, false))
522 return false;
523 return true;
524}
525
526#ifdef __clang__
527#pragma clang diagnostic pop
528#endif
529
530#ifdef __clang__
531#pragma clang diagnostic push
532#pragma clang diagnostic ignored "-Wmissing-field-initializers"
533#endif
534
535// __dynamic_cast
536
537// static_ptr: pointer to an object of type static_type; nonnull, and since the
538// object is polymorphic, *(void**)static_ptr is a virtual table pointer.
539// static_ptr is &v in the expression dynamic_cast<T>(v).
540// static_type: static type of the object pointed to by static_ptr.
541// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)").
542// src2dst_offset: a static hint about the location of the
543// source subobject with respect to the complete object;
544// special negative values are:
545// -1: no hint
546// -2: static_type is not a public base of dst_type
547// -3: static_type is a multiple public base type but never a
548// virtual base type
549// otherwise, the static_type type is a unique public nonvirtual
550// base type of dst_type at offset src2dst_offset from the
551// origin of dst_type.
552//
553// (dynamic_ptr, dynamic_type) are the run time type of the complete object
554// referred to by static_ptr and a pointer to it. These can be found from
555// static_ptr for polymorphic types.
556// static_type is guaranteed to be a polymorphic type.
557//
558// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each
559// node of the tree represents a base class/object of its parent (or parents) below.
560// Each node is uniquely represented by a pointer to the object, and a pointer
561// to a type_info - its type. Different nodes may have the same pointer and
562// different nodes may have the same type. But only one node has a specific
563// (pointer-value, type) pair. In C++ two objects of the same type can not
564// share the same address.
565//
566// There are two flavors of nodes which have the type dst_type:
567// 1. Those that are derived from (below) (static_ptr, static_type).
568// 2. Those that are not derived from (below) (static_ptr, static_type).
569//
570// Invariants of the DAG:
571//
572// There is at least one path from the root (dynamic_ptr, dynamic_type) to
573// the node (static_ptr, static_type). This path may or may not be public.
574// There may be more than one such path (some public some not). Such a path may
575// or may not go through a node having type dst_type.
576//
577// No node of type T appears above a node of the same type. That means that
578// there is only one node with dynamic_type. And if dynamic_type == dst_type,
579// then there is only one dst_type in the DAG.
580//
581// No node of type dst_type appears above a node of type static_type. Such
582// DAG's are possible in C++, but the compiler computes those dynamic_casts at
583// compile time, and only calls __dynamic_cast when dst_type lies below
584// static_type in the DAG.
585//
586// dst_type != static_type: The compiler computes the dynamic_cast in this case too.
587// dynamic_type != static_type: The compiler computes the dynamic_cast in this case too.
588//
589// Returns:
590//
591// If there is exactly one dst_type of flavor 1, and
592// If there is a public path from that dst_type to (static_ptr, static_type), or
593// If there are 0 dst_types of flavor 2, and there is a public path from
594// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public
595// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return
596// a pointer to that dst_type.
597// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and
598// if there is a public path from (dynamic_ptr, dynamic_type) to
599// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)
600// to the one dst_type, then return a pointer to that one dst_type.
601// Else return nullptr.
602//
603// If dynamic_type == dst_type, then the above algorithm collapses to the
604// following cheaper algorithm:
605//
606// If there is a public path from (dynamic_ptr, dynamic_type) to
607// (static_ptr, static_type), then return dynamic_ptr.
608// Else return nullptr.
609
610extern "C" _LIBCXXABI_FUNC_VIS void *
611__dynamic_cast(const void *static_ptr, const __class_type_info *static_type,
612 const __class_type_info *dst_type,
613 std::ptrdiff_t src2dst_offset) {
614 // Possible future optimization: Take advantage of src2dst_offset
615
616 // Get (dynamic_ptr, dynamic_type) from static_ptr
617 void **vtable = *static_cast<void ** const *>(static_ptr);
618 ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
619 const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
620 const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
621
622 // Initialize answer to nullptr. This will be changed from the search
623 // results if a non-null answer is found. Regardless, this is what will
624 // be returned.
625 const void* dst_ptr = 0;
626 // Initialize info struct for this search.
627 __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
628
629 // Find out if we can use a giant short cut in the search
630 if (is_equal(dynamic_type, dst_type, false))
631 {
632 // Using giant short cut. Add that information to info.
633 info.number_of_dst_type = 1;
634 // Do the search
635 dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
636#ifdef _LIBCXX_DYNAMIC_FALLBACK
637 // The following if should always be false because we should definitely
638 // find (static_ptr, static_type), either on a public or private path
639 if (info.path_dst_ptr_to_static_ptr == unknown)
640 {
641 // We get here only if there is some kind of visibility problem
642 // in client code.
643 syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
644 "should have public visibility. At least one of them is hidden. %s"
645 ", %s.\n", static_type->name(), dynamic_type->name());
646 // Redo the search comparing type_info's using strcmp
647 info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
648 info.number_of_dst_type = 1;
649 dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
650 }
651#endif // _LIBCXX_DYNAMIC_FALLBACK
652 // Query the search.
653 if (info.path_dst_ptr_to_static_ptr == public_path)
654 dst_ptr = dynamic_ptr;
655 }
656 else
657 {
658 // Not using giant short cut. Do the search
659 dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
660 #ifdef _LIBCXX_DYNAMIC_FALLBACK
661 // The following if should always be false because we should definitely
662 // find (static_ptr, static_type), either on a public or private path
663 if (info.path_dst_ptr_to_static_ptr == unknown &&
664 info.path_dynamic_ptr_to_static_ptr == unknown)
665 {
666 syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
667 "has hidden visibility or is defined in more than one translation "
668 "unit. They should all have public visibility. "
669 "%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
670 dst_type->name());
671 // Redo the search comparing type_info's using strcmp
672 info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
673 dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
674 }
675#endif // _LIBCXX_DYNAMIC_FALLBACK
676 // Query the search.
677 switch (info.number_to_static_ptr)
678 {
679 case 0:
680 if (info.number_to_dst_ptr == 1 &&
681 info.path_dynamic_ptr_to_static_ptr == public_path &&
682 info.path_dynamic_ptr_to_dst_ptr == public_path)
683 dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
684 break;
685 case 1:
686 if (info.path_dst_ptr_to_static_ptr == public_path ||
687 (
688 info.number_to_dst_ptr == 0 &&
689 info.path_dynamic_ptr_to_static_ptr == public_path &&
690 info.path_dynamic_ptr_to_dst_ptr == public_path
691 )
692 )
693 dst_ptr = info.dst_ptr_leading_to_static_ptr;
694 break;
695 }
696 }
697 return const_cast<void*>(dst_ptr);
698}
699
700#ifdef __clang__
701#pragma clang diagnostic pop
702#endif
703
704// Call this function when you hit a static_type which is a base (above) a dst_type.
705// Let caller know you hit a static_type. But only start recording details if
706// this is (static_ptr, static_type) -- the node we are casting from.
707// If this is (static_ptr, static_type)
708// Record the path (public or not) from the dst_type to here. There may be
709// multiple paths from the same dst_type to here, record the "most public" one.
710// Record the dst_ptr as pointing to (static_ptr, static_type).
711// If more than one (dst_ptr, dst_type) points to (static_ptr, static_type),
712// then mark this dyanmic_cast as ambiguous and stop the search.
713void
714__class_type_info::process_static_type_above_dst(__dynamic_cast_info* info,
715 const void* dst_ptr,
716 const void* current_ptr,
717 int path_below) const
718{
719 // Record that we found a static_type
720 info->found_any_static_type = true;
721 if (current_ptr == info->static_ptr)
722 {
723 // Record that we found (static_ptr, static_type)
724 info->found_our_static_ptr = true;
725 if (info->dst_ptr_leading_to_static_ptr == 0)
726 {
727 // First time here
728 info->dst_ptr_leading_to_static_ptr = dst_ptr;
729 info->path_dst_ptr_to_static_ptr = path_below;
730 info->number_to_static_ptr = 1;
731 // If there is only one dst_type in the entire tree and the path from
732 // there to here is public then we are done!
733 if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
734 info->search_done = true;
735 }
736 else if (info->dst_ptr_leading_to_static_ptr == dst_ptr)
737 {
738 // We've been here before. Update path to "most public"
739 if (info->path_dst_ptr_to_static_ptr == not_public_path)
740 info->path_dst_ptr_to_static_ptr = path_below;
741 // If there is only one dst_type in the entire tree and the path from
742 // there to here is public then we are done!
743 if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
744 info->search_done = true;
745 }
746 else
747 {
748 // We've detected an ambiguous cast from (static_ptr, static_type)
749 // to a dst_type
750 info->number_to_static_ptr += 1;
751 info->search_done = true;
752 }
753 }
754}
755
756// Call this function when you hit a static_type which is not a base (above) a dst_type.
757// If this is (static_ptr, static_type)
758// Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be
759// multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one.
760void
761__class_type_info::process_static_type_below_dst(__dynamic_cast_info* info,
762 const void* current_ptr,
763 int path_below) const
764{
765 if (current_ptr == info->static_ptr)
766 {
767 // Record the most public path from (dynamic_ptr, dynamic_type) to
768 // (static_ptr, static_type)
769 if (info->path_dynamic_ptr_to_static_ptr != public_path)
770 info->path_dynamic_ptr_to_static_ptr = path_below;
771 }
772}
773
774// Call this function when searching below a dst_type node. This function searches
775// for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes.
776// If it finds a static_type node, there is no need to further search base classes
777// above.
778// If it finds a dst_type node it should search base classes using search_above_dst
779// to find out if this dst_type points to (static_ptr, static_type) or not.
780// Either way, the dst_type is recorded as one of two "flavors": one that does
781// or does not point to (static_ptr, static_type).
782// If this is neither a static_type nor a dst_type node, continue searching
783// base classes above.
784// All the hoopla surrounding the search code is doing nothing but looking for
785// excuses to stop the search prematurely (break out of the for-loop). That is,
786// the algorithm below is simply an optimization of this:
787// void
788// __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
789// const void* current_ptr,
790// int path_below) const
791// {
792// typedef const __base_class_type_info* Iter;
793// if (this == info->static_type)
794// process_static_type_below_dst(info, current_ptr, path_below);
795// else if (this == info->dst_type)
796// {
797// // Record the most public access path that got us here
798// if (info->path_dynamic_ptr_to_dst_ptr != public_path)
799// info->path_dynamic_ptr_to_dst_ptr = path_below;
800// bool does_dst_type_point_to_our_static_type = false;
801// for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p)
802// {
803// p->search_above_dst(info, current_ptr, current_ptr, public_path);
804// if (info->found_our_static_ptr)
805// does_dst_type_point_to_our_static_type = true;
806// // break out early here if you can detect it doesn't matter if you do
807// }
808// if (!does_dst_type_point_to_our_static_type)
809// {
810// // We found a dst_type that doesn't point to (static_ptr, static_type)
811// // So record the address of this dst_ptr and increment the
812// // count of the number of such dst_types found in the tree.
813// info->dst_ptr_not_leading_to_static_ptr = current_ptr;
814// info->number_to_dst_ptr += 1;
815// }
816// }
817// else
818// {
819// // This is not a static_type and not a dst_type.
820// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
821// {
822// p->search_below_dst(info, current_ptr, public_path);
823// // break out early here if you can detect it doesn't matter if you do
824// }
825// }
826// }
827void
828__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
829 const void* current_ptr,
830 int path_below,
831 bool use_strcmp) const
832{
833 typedef const __base_class_type_info* Iter;
834 if (is_equal(this, info->static_type, use_strcmp))
835 process_static_type_below_dst(info, current_ptr, path_below);
836 else if (is_equal(this, info->dst_type, use_strcmp))
837 {
838 // We've been here before if we've recorded current_ptr in one of these
839 // two places:
840 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
841 current_ptr == info->dst_ptr_not_leading_to_static_ptr)
842 {
843 // We've seen this node before, and therefore have already searched
844 // its base classes above.
845 // Update path to here that is "most public".
846 if (path_below == public_path)
847 info->path_dynamic_ptr_to_dst_ptr = public_path;
848 }
849 else // We have haven't been here before
850 {
851 // Record the access path that got us here
852 // If there is more than one dst_type this path doesn't matter.
853 info->path_dynamic_ptr_to_dst_ptr = path_below;
854 bool does_dst_type_point_to_our_static_type = false;
855 // Only search above here if dst_type derives from static_type, or
856 // if it is unknown if dst_type derives from static_type.
857 if (info->is_dst_type_derived_from_static_type != no)
858 {
859 // Set up flags to record results from all base classes
860 bool is_dst_type_derived_from_static_type = false;
861
862 // We've found a dst_type with a potentially public path to here.
863 // We have to assume the path is public because it may become
864 // public later (if we get back to here with a public path).
865 // We can stop looking above if:
866 // 1. We've found a public path to (static_ptr, static_type).
867 // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
868 // This is detected at the (static_ptr, static_type).
869 // 3. We can prove that there is no public path to (static_ptr, static_type)
870 // above here.
871 const Iter e = __base_info + __base_count;
872 for (Iter p = __base_info; p < e; ++p)
873 {
874 // Zero out found flags
875 info->found_our_static_ptr = false;
876 info->found_any_static_type = false;
877 p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
878 if (info->search_done)
879 break;
880 if (info->found_any_static_type)
881 {
882 is_dst_type_derived_from_static_type = true;
883 if (info->found_our_static_ptr)
884 {
885 does_dst_type_point_to_our_static_type = true;
886 // If we found what we're looking for, stop looking above.
887 if (info->path_dst_ptr_to_static_ptr == public_path)
888 break;
889 // We found a private path to (static_ptr, static_type)
890 // If there is no diamond then there is only one path
891 // to (static_ptr, static_type) and we just found it.
892 if (!(__flags & __diamond_shaped_mask))
893 break;
894 }
895 else
896 {
897 // If we found a static_type that isn't the one we're looking
898 // for, and if there are no repeated types above here,
899 // then stop looking.
900 if (!(__flags & __non_diamond_repeat_mask))
901 break;
902 }
903 }
904 }
905 // If we found no static_type,s then dst_type doesn't derive
906 // from static_type, else it does. Record this result so that
907 // next time we hit a dst_type we will know not to search above
908 // it if it doesn't derive from static_type.
909 if (is_dst_type_derived_from_static_type)
910 info->is_dst_type_derived_from_static_type = yes;
911 else
912 info->is_dst_type_derived_from_static_type = no;
913 }
914 if (!does_dst_type_point_to_our_static_type)
915 {
916 // We found a dst_type that doesn't point to (static_ptr, static_type)
917 // So record the address of this dst_ptr and increment the
918 // count of the number of such dst_types found in the tree.
919 info->dst_ptr_not_leading_to_static_ptr = current_ptr;
920 info->number_to_dst_ptr += 1;
921 // If there exists another dst with a private path to
922 // (static_ptr, static_type), then the cast from
923 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous,
924 // so stop search.
925 if (info->number_to_static_ptr == 1 &&
926 info->path_dst_ptr_to_static_ptr == not_public_path)
927 info->search_done = true;
928 }
929 }
930 }
931 else
932 {
933 // This is not a static_type and not a dst_type.
934 const Iter e = __base_info + __base_count;
935 Iter p = __base_info;
936 p->search_below_dst(info, current_ptr, path_below, use_strcmp);
937 if (++p < e)
938 {
939 if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)
940 {
941 // If there are multiple paths to a base above from here, or if
942 // a dst_type pointing to (static_ptr, static_type) has been found,
943 // then there is no way to break out of this loop early unless
944 // something below detects the search is done.
945 do
946 {
947 if (info->search_done)
948 break;
949 p->search_below_dst(info, current_ptr, path_below, use_strcmp);
950 } while (++p < e);
951 }
952 else if (__flags & __non_diamond_repeat_mask)
953 {
954 // There are not multiple paths to any base class from here and a
955 // dst_type pointing to (static_ptr, static_type) has not yet been
956 // found.
957 do
958 {
959 if (info->search_done)
960 break;
961 // If we just found a dst_type with a public path to (static_ptr, static_type),
962 // then the only reason to continue the search is to make sure
963 // no other dst_type points to (static_ptr, static_type).
964 // If !diamond, then we don't need to search here.
965 if (info->number_to_static_ptr == 1 &&
966 info->path_dst_ptr_to_static_ptr == public_path)
967 break;
968 p->search_below_dst(info, current_ptr, path_below, use_strcmp);
969 } while (++p < e);
970 }
971 else
972 {
973 // There are no repeated types above this node.
974 // There are no nodes with multiple parents above this node.
975 // no dst_type has been found to (static_ptr, static_type)
976 do
977 {
978 if (info->search_done)
979 break;
980 // If we just found a dst_type with a public path to (static_ptr, static_type),
981 // then the only reason to continue the search is to make sure sure
982 // no other dst_type points to (static_ptr, static_type).
983 // If !diamond, then we don't need to search here.
984 // if we just found a dst_type with a private path to (static_ptr, static_type),
985 // then we're only looking for a public path to (static_ptr, static_type)
986 // and to check for other dst_types.
987 // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type)
988 // and not a dst_type under here.
989 if (info->number_to_static_ptr == 1)
990 break;
991 p->search_below_dst(info, current_ptr, path_below, use_strcmp);
992 } while (++p < e);
993 }
994 }
995 }
996}
997
998// This is the same algorithm as __vmi_class_type_info::search_below_dst but
999// simplified to the case that there is only a single base class.
1000void
1001__si_class_type_info::search_below_dst(__dynamic_cast_info* info,
1002 const void* current_ptr,
1003 int path_below,
1004 bool use_strcmp) const
1005{
1006 if (is_equal(this, info->static_type, use_strcmp))
1007 process_static_type_below_dst(info, current_ptr, path_below);
1008 else if (is_equal(this, info->dst_type, use_strcmp))
1009 {
1010 // We've been here before if we've recorded current_ptr in one of these
1011 // two places:
1012 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
1013 current_ptr == info->dst_ptr_not_leading_to_static_ptr)
1014 {
1015 // We've seen this node before, and therefore have already searched
1016 // its base classes above.
1017 // Update path to here that is "most public".
1018 if (path_below == public_path)
1019 info->path_dynamic_ptr_to_dst_ptr = public_path;
1020 }
1021 else // We have haven't been here before
1022 {
1023 // Record the access path that got us here
1024 // If there is more than one dst_type this path doesn't matter.
1025 info->path_dynamic_ptr_to_dst_ptr = path_below;
1026 bool does_dst_type_point_to_our_static_type = false;
1027 // Only search above here if dst_type derives from static_type, or
1028 // if it is unknown if dst_type derives from static_type.
1029 if (info->is_dst_type_derived_from_static_type != no)
1030 {
1031 // Set up flags to record results from all base classes
1032 bool is_dst_type_derived_from_static_type = false;
1033 // Zero out found flags
1034 info->found_our_static_ptr = false;
1035 info->found_any_static_type = false;
1036 __base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
1037 if (info->found_any_static_type)
1038 {
1039 is_dst_type_derived_from_static_type = true;
1040 if (info->found_our_static_ptr)
1041 does_dst_type_point_to_our_static_type = true;
1042 }
1043 // If we found no static_type,s then dst_type doesn't derive
1044 // from static_type, else it does. Record this result so that
1045 // next time we hit a dst_type we will know not to search above
1046 // it if it doesn't derive from static_type.
1047 if (is_dst_type_derived_from_static_type)
1048 info->is_dst_type_derived_from_static_type = yes;
1049 else
1050 info->is_dst_type_derived_from_static_type = no;
1051 }
1052 if (!does_dst_type_point_to_our_static_type)
1053 {
1054 // We found a dst_type that doesn't point to (static_ptr, static_type)
1055 // So record the address of this dst_ptr and increment the
1056 // count of the number of such dst_types found in the tree.
1057 info->dst_ptr_not_leading_to_static_ptr = current_ptr;
1058 info->number_to_dst_ptr += 1;
1059 // If there exists another dst with a private path to
1060 // (static_ptr, static_type), then the cast from
1061 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
1062 if (info->number_to_static_ptr == 1 &&
1063 info->path_dst_ptr_to_static_ptr == not_public_path)
1064 info->search_done = true;
1065 }
1066 }
1067 }
1068 else
1069 {
1070 // This is not a static_type and not a dst_type
1071 __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp);
1072 }
1073}
1074
1075// This is the same algorithm as __vmi_class_type_info::search_below_dst but
1076// simplified to the case that there is no base class.
1077void
1078__class_type_info::search_below_dst(__dynamic_cast_info* info,
1079 const void* current_ptr,
1080 int path_below,
1081 bool use_strcmp) const
1082{
1083 if (is_equal(this, info->static_type, use_strcmp))
1084 process_static_type_below_dst(info, current_ptr, path_below);
1085 else if (is_equal(this, info->dst_type, use_strcmp))
1086 {
1087 // We've been here before if we've recorded current_ptr in one of these
1088 // two places:
1089 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
1090 current_ptr == info->dst_ptr_not_leading_to_static_ptr)
1091 {
1092 // We've seen this node before, and therefore have already searched
1093 // its base classes above.
1094 // Update path to here that is "most public".
1095 if (path_below == public_path)
1096 info->path_dynamic_ptr_to_dst_ptr = public_path;
1097 }
1098 else // We have haven't been here before
1099 {
1100 // Record the access path that got us here
1101 // If there is more than one dst_type this path doesn't matter.
1102 info->path_dynamic_ptr_to_dst_ptr = path_below;
1103 // We found a dst_type that doesn't point to (static_ptr, static_type)
1104 // So record the address of this dst_ptr and increment the
1105 // count of the number of such dst_types found in the tree.
1106 info->dst_ptr_not_leading_to_static_ptr = current_ptr;
1107 info->number_to_dst_ptr += 1;
1108 // If there exists another dst with a private path to
1109 // (static_ptr, static_type), then the cast from
1110 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
1111 if (info->number_to_static_ptr == 1 &&
1112 info->path_dst_ptr_to_static_ptr == not_public_path)
1113 info->search_done = true;
1114 // We found that dst_type does not derive from static_type
1115 info->is_dst_type_derived_from_static_type = no;
1116 }
1117 }
1118}
1119
1120// Call this function when searching above a dst_type node. This function searches
1121// for a public path to (static_ptr, static_type).
1122// This function is guaranteed not to find a node of type dst_type.
1123// Theoretically this is a very simple function which just stops if it finds a
1124// static_type node: All the hoopla surrounding the search code is doing
1125// nothing but looking for excuses to stop the search prematurely (break out of
1126// the for-loop). That is, the algorithm below is simply an optimization of this:
1127// void
1128// __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
1129// const void* dst_ptr,
1130// const void* current_ptr,
1131// int path_below) const
1132// {
1133// if (this == info->static_type)
1134// process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
1135// else
1136// {
1137// typedef const __base_class_type_info* Iter;
1138// // This is not a static_type and not a dst_type
1139// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
1140// {
1141// p->search_above_dst(info, dst_ptr, current_ptr, public_path);
1142// // break out early here if you can detect it doesn't matter if you do
1143// }
1144// }
1145// }
1146void
1147__vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
1148 const void* dst_ptr,
1149 const void* current_ptr,
1150 int path_below,
1151 bool use_strcmp) const
1152{
1153 if (is_equal(this, info->static_type, use_strcmp))
1154 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
1155 else
1156 {
1157 typedef const __base_class_type_info* Iter;
1158 // This is not a static_type and not a dst_type
1159 // Save flags so they can be restored when returning to nodes below.
1160 bool found_our_static_ptr = info->found_our_static_ptr;
1161 bool found_any_static_type = info->found_any_static_type;
1162 // We've found a dst_type below with a path to here. If the path
1163 // to here is not public, there may be another path to here that
1164 // is public. So we have to assume that the path to here is public.
1165 // We can stop looking above if:
1166 // 1. We've found a public path to (static_ptr, static_type).
1167 // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
1168 // This is detected at the (static_ptr, static_type).
1169 // 3. We can prove that there is no public path to (static_ptr, static_type)
1170 // above here.
1171 const Iter e = __base_info + __base_count;
1172 Iter p = __base_info;
1173 // Zero out found flags
1174 info->found_our_static_ptr = false;
1175 info->found_any_static_type = false;
1176 p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
1177 found_our_static_ptr |= info->found_our_static_ptr;
1178 found_any_static_type |= info->found_any_static_type;
1179 if (++p < e)
1180 {
1181 do
1182 {
1183 if (info->search_done)
1184 break;
1185 if (info->found_our_static_ptr)
1186 {
1187 // If we found what we're looking for, stop looking above.
1188 if (info->path_dst_ptr_to_static_ptr == public_path)
1189 break;
1190 // We found a private path to (static_ptr, static_type)
1191 // If there is no diamond then there is only one path
1192 // to (static_ptr, static_type) from here and we just found it.
1193 if (!(__flags & __diamond_shaped_mask))
1194 break;
1195 }
1196 else if (info->found_any_static_type)
1197 {
1198 // If we found a static_type that isn't the one we're looking
1199 // for, and if there are no repeated types above here,
1200 // then stop looking.
1201 if (!(__flags & __non_diamond_repeat_mask))
1202 break;
1203 }
1204 // Zero out found flags
1205 info->found_our_static_ptr = false;
1206 info->found_any_static_type = false;
1207 p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
1208 found_our_static_ptr |= info->found_our_static_ptr;
1209 found_any_static_type |= info->found_any_static_type;
1210 } while (++p < e);
1211 }
1212 // Restore flags
1213 info->found_our_static_ptr = found_our_static_ptr;
1214 info->found_any_static_type = found_any_static_type;
1215 }
1216}
1217
1218// This is the same algorithm as __vmi_class_type_info::search_above_dst but
1219// simplified to the case that there is only a single base class.
1220void
1221__si_class_type_info::search_above_dst(__dynamic_cast_info* info,
1222 const void* dst_ptr,
1223 const void* current_ptr,
1224 int path_below,
1225 bool use_strcmp) const
1226{
1227 if (is_equal(this, info->static_type, use_strcmp))
1228 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
1229 else
1230 __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
1231}
1232
1233// This is the same algorithm as __vmi_class_type_info::search_above_dst but
1234// simplified to the case that there is no base class.
1235void
1236__class_type_info::search_above_dst(__dynamic_cast_info* info,
1237 const void* dst_ptr,
1238 const void* current_ptr,
1239 int path_below,
1240 bool use_strcmp) const
1241{
1242 if (is_equal(this, info->static_type, use_strcmp))
1243 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
1244}
1245
1246// The search functions for __base_class_type_info are simply convenience
1247// functions for adjusting the current_ptr and path_below as the search is
1248// passed up to the base class node.
1249
1250void
1251__base_class_type_info::search_above_dst(__dynamic_cast_info* info,
1252 const void* dst_ptr,
1253 const void* current_ptr,
1254 int path_below,
1255 bool use_strcmp) const
1256{
1257 ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
1258 if (__offset_flags & __virtual_mask)
1259 {
1260 const char* vtable = *static_cast<const char*const*>(current_ptr);
1261 offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
1262 }
1263 __base_type->search_above_dst(info, dst_ptr,
1264 static_cast<const char*>(current_ptr) + offset_to_base,
1265 (__offset_flags & __public_mask) ?
1266 path_below :
1267 not_public_path,
1268 use_strcmp);
1269}
1270
1271void
1272__base_class_type_info::search_below_dst(__dynamic_cast_info* info,
1273 const void* current_ptr,
1274 int path_below,
1275 bool use_strcmp) const
1276{
1277 ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
1278 if (__offset_flags & __virtual_mask)
1279 {
1280 const char* vtable = *static_cast<const char*const*>(current_ptr);
1281 offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
1282 }
1283 __base_type->search_below_dst(info,
1284 static_cast<const char*>(current_ptr) + offset_to_base,
1285 (__offset_flags & __public_mask) ?
1286 path_below :
1287 not_public_path,
1288 use_strcmp);
1289}
1290
1291} // __cxxabiv1
1292