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