1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "private_typeinfo.h" |
10 | |
11 | // The flag _LIBCXXABI_FORGIVING_DYNAMIC_CAST is used to make dynamic_cast |
12 | // more forgiving when type_info's mistakenly have hidden visibility and |
13 | // thus multiple type_infos can exist for a single type. |
14 | // |
15 | // When _LIBCXXABI_FORGIVING_DYNAMIC_CAST 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 _LIBCXXABI_FORGIVING_DYNAMIC_CAST 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 | // _LIBCXXABI_FORGIVING_DYNAMIC_CAST 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 _LIBCXXABI_FORGIVING_DYNAMIC_CAST does not help since can_catch() calls |
42 | // is_equal() with use_strcmp=false so the string names are not compared. |
43 | |
44 | #include <cassert> |
45 | #include <cstddef> |
46 | #include <cstdint> |
47 | #include <string.h> |
48 | |
49 | #include "abort_message.h" |
50 | |
51 | #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST |
52 | #include <sys/syslog.h> |
53 | #include <atomic> |
54 | #endif |
55 | |
56 | #if __has_feature(ptrauth_calls) |
57 | #include <ptrauth.h> |
58 | #endif |
59 | |
60 | template <typename T> |
61 | static inline T* strip_vtable(T* vtable) { |
62 | #if __has_feature(ptrauth_calls) |
63 | vtable = ptrauth_strip(vtable, ptrauth_key_cxx_vtable_pointer); |
64 | #endif |
65 | return vtable; |
66 | } |
67 | |
68 | static inline |
69 | bool |
70 | is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp) |
71 | { |
72 | // Use std::type_info's default comparison unless we've explicitly asked |
73 | // for strcmp. |
74 | if (!use_strcmp) |
75 | return *x == *y; |
76 | // Still allow pointer equality to short circut. |
77 | return x == y || strcmp(s1: x->name(), s2: y->name()) == 0; |
78 | } |
79 | |
80 | static inline ptrdiff_t update_offset_to_base(const char* vtable, |
81 | ptrdiff_t offset_to_base) { |
82 | #if __has_feature(cxx_abi_relative_vtable) |
83 | // VTable components are 32 bits in the relative vtables ABI. |
84 | return *reinterpret_cast<const int32_t*>(vtable + offset_to_base); |
85 | #else |
86 | return *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); |
87 | #endif |
88 | } |
89 | |
90 | namespace __cxxabiv1 |
91 | { |
92 | |
93 | namespace { |
94 | |
95 | struct derived_object_info { |
96 | const void* dynamic_ptr; |
97 | const __class_type_info* dynamic_type; |
98 | std::ptrdiff_t offset_to_derived; |
99 | }; |
100 | |
101 | /// A helper function that gets (dynamic_ptr, dynamic_type, offset_to_derived) from static_ptr. |
102 | void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr) |
103 | { |
104 | #if __has_feature(cxx_abi_relative_vtable) |
105 | // The vtable address will point to the first virtual function, which is 8 |
106 | // bytes after the start of the vtable (4 for the offset from top + 4 for |
107 | // the typeinfo component). |
108 | const int32_t* vtable = |
109 | *reinterpret_cast<const int32_t* const*>(static_ptr); |
110 | info->offset_to_derived = static_cast<std::ptrdiff_t>(vtable[-2]); |
111 | info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived; |
112 | |
113 | // The typeinfo component is now a relative offset to a proxy. |
114 | int32_t offset_to_ti_proxy = vtable[-1]; |
115 | const uint8_t* ptr_to_ti_proxy = |
116 | reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy; |
117 | info->dynamic_type = *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy)); |
118 | #else |
119 | void** vtable = strip_vtable(vtable: *static_cast<void** const*>(static_ptr)); |
120 | info->offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]); |
121 | info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived; |
122 | info->dynamic_type = static_cast<const __class_type_info*>(vtable[-1]); |
123 | #endif |
124 | } |
125 | |
126 | /// A helper function for __dynamic_cast that casts a base sub-object pointer |
127 | /// to the object's dynamic type. |
128 | /// |
129 | /// This function returns the casting result directly. No further processing |
130 | /// required. |
131 | /// |
132 | /// Specifically, this function can only be called if the following pre- |
133 | /// condition holds: |
134 | /// * The dynamic type of the object pointed to by `static_ptr` is exactly |
135 | /// the same as `dst_type`. |
136 | const void* dyn_cast_to_derived(const void* static_ptr, |
137 | const void* dynamic_ptr, |
138 | const __class_type_info* static_type, |
139 | const __class_type_info* dst_type, |
140 | std::ptrdiff_t offset_to_derived, |
141 | std::ptrdiff_t src2dst_offset) |
142 | { |
143 | // We're downcasting from src_type to the complete object's dynamic type. |
144 | // This is a really hot path that can be further optimized with the |
145 | // `src2dst_offset` hint. |
146 | // In such a case, dynamic_ptr already gives the casting result if the |
147 | // casting ever succeeds. All we have to do now is to check static_ptr |
148 | // points to a public base sub-object of dynamic_ptr. |
149 | |
150 | if (src2dst_offset >= 0) |
151 | { |
152 | // The static type is a unique public non-virtual base type of |
153 | // dst_type at offset `src2dst_offset` from the origin of dst. |
154 | // Note that there might be other non-public static_type bases. The |
155 | // hint only guarantees that the public base is non-virtual and |
156 | // unique. So we have to check whether static_ptr points to that |
157 | // unique public base sub-object. |
158 | if (offset_to_derived != -src2dst_offset) |
159 | return nullptr; |
160 | return dynamic_ptr; |
161 | } |
162 | |
163 | if (src2dst_offset == -2) |
164 | { |
165 | // static_type is not a public base of dst_type. |
166 | return nullptr; |
167 | } |
168 | |
169 | // If src2dst_offset == -3, then: |
170 | // src_type is a multiple public base type but never a virtual |
171 | // base type. We can't conclude that static_ptr points to those |
172 | // public base sub-objects because there might be other non- |
173 | // public static_type bases. The search is inevitable. |
174 | |
175 | // Fallback to the slow path to check that static_type is a public |
176 | // base type of dynamic_type. |
177 | // Using giant short cut. Add that information to info. |
178 | __dynamic_cast_info info = {.dst_type: dst_type, .static_ptr: static_ptr, .static_type: static_type, .src2dst_offset: src2dst_offset, .dst_ptr_leading_to_static_ptr: 0, .dst_ptr_not_leading_to_static_ptr: 0, .path_dst_ptr_to_static_ptr: 0, .path_dynamic_ptr_to_static_ptr: 0, .path_dynamic_ptr_to_dst_ptr: 0, .number_to_static_ptr: 0, .number_to_dst_ptr: 0, .is_dst_type_derived_from_static_type: 0, |
179 | .number_of_dst_type: 1, // number_of_dst_type |
180 | .found_our_static_ptr: false, .found_any_static_type: false, .search_done: false, .have_object: true, .vbase_cookie: nullptr}; |
181 | // Do the search |
182 | dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false); |
183 | #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST |
184 | // The following if should always be false because we should |
185 | // definitely find (static_ptr, static_type), either on a public |
186 | // or private path |
187 | if (info.path_dst_ptr_to_static_ptr == unknown) |
188 | { |
189 | // We get here only if there is some kind of visibility problem |
190 | // in client code. |
191 | static_assert(std::atomic<size_t>::is_always_lock_free, "" ); |
192 | static std::atomic<size_t> error_count(0); |
193 | size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed); |
194 | if ((error_count_snapshot & (error_count_snapshot-1)) == 0) |
195 | syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " |
196 | "should have public visibility. At least one of them is hidden. %s" |
197 | ", %s.\n" , static_type->name(), dst_type->name()); |
198 | // Redo the search comparing type_info's using strcmp |
199 | info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, |
200 | 0, 0, 0, false, false, false, true, nullptr}; |
201 | info.number_of_dst_type = 1; |
202 | dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true); |
203 | } |
204 | #endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST |
205 | // Query the search. |
206 | if (info.path_dst_ptr_to_static_ptr != public_path) |
207 | return nullptr; |
208 | |
209 | return dynamic_ptr; |
210 | } |
211 | |
212 | /// A helper function for __dynamic_cast that tries to perform a downcast |
213 | /// before giving up and falling back to the slow path. |
214 | const void* dyn_cast_try_downcast(const void* static_ptr, |
215 | const void* dynamic_ptr, |
216 | const __class_type_info* dst_type, |
217 | const __class_type_info* dynamic_type, |
218 | std::ptrdiff_t src2dst_offset) |
219 | { |
220 | if (src2dst_offset < 0) |
221 | { |
222 | // We can only optimize the case if the static type is a unique public |
223 | // base of dst_type. Give up. |
224 | return nullptr; |
225 | } |
226 | |
227 | // Pretend there is a dst_type object that leads to static_ptr. Later we |
228 | // will check whether this imagined dst_type object exists. If it exists |
229 | // then it will be the casting result. |
230 | const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset; |
231 | |
232 | if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) < reinterpret_cast<std::intptr_t>(dynamic_ptr)) |
233 | { |
234 | // The imagined dst_type object does not exist. Bail-out quickly. |
235 | return nullptr; |
236 | } |
237 | |
238 | // Try to search a path from dynamic_type to dst_type. |
239 | __dynamic_cast_info dynamic_to_dst_info = {.dst_type: dynamic_type, |
240 | .static_ptr: dst_ptr_to_static, |
241 | .static_type: dst_type, |
242 | .src2dst_offset: src2dst_offset, |
243 | .dst_ptr_leading_to_static_ptr: 0, |
244 | .dst_ptr_not_leading_to_static_ptr: 0, |
245 | .path_dst_ptr_to_static_ptr: 0, |
246 | .path_dynamic_ptr_to_static_ptr: 0, |
247 | .path_dynamic_ptr_to_dst_ptr: 0, |
248 | .number_to_static_ptr: 0, |
249 | .number_to_dst_ptr: 0, |
250 | .is_dst_type_derived_from_static_type: 0, |
251 | .number_of_dst_type: 1, // number_of_dst_type |
252 | .found_our_static_ptr: false, |
253 | .found_any_static_type: false, |
254 | .search_done: false, |
255 | .have_object: true, |
256 | .vbase_cookie: nullptr}; |
257 | dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false); |
258 | if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) { |
259 | // We have found at least one path from dynamic_ptr to dst_ptr. The |
260 | // downcast can succeed. |
261 | return dst_ptr_to_static; |
262 | } |
263 | |
264 | return nullptr; |
265 | } |
266 | |
267 | const void* dyn_cast_slow(const void* static_ptr, |
268 | const void* dynamic_ptr, |
269 | const __class_type_info* static_type, |
270 | const __class_type_info* dst_type, |
271 | const __class_type_info* dynamic_type, |
272 | std::ptrdiff_t src2dst_offset) |
273 | { |
274 | // Not using giant short cut. Do the search |
275 | |
276 | // Initialize info struct for this search. |
277 | __dynamic_cast_info info = {.dst_type: dst_type, .static_ptr: static_ptr, .static_type: static_type, .src2dst_offset: src2dst_offset, .dst_ptr_leading_to_static_ptr: 0, .dst_ptr_not_leading_to_static_ptr: 0, .path_dst_ptr_to_static_ptr: 0, .path_dynamic_ptr_to_static_ptr: 0, .path_dynamic_ptr_to_dst_ptr: 0, .number_to_static_ptr: 0, |
278 | .number_to_dst_ptr: 0, .is_dst_type_derived_from_static_type: 0, .number_of_dst_type: 0, .found_our_static_ptr: false, .found_any_static_type: false, .search_done: false, .have_object: true, .vbase_cookie: nullptr}; |
279 | |
280 | dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false); |
281 | #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST |
282 | // The following if should always be false because we should |
283 | // definitely find (static_ptr, static_type), either on a public |
284 | // or private path |
285 | if (info.path_dst_ptr_to_static_ptr == unknown && |
286 | info.path_dynamic_ptr_to_static_ptr == unknown) |
287 | { |
288 | static_assert(std::atomic<size_t>::is_always_lock_free, "" ); |
289 | static std::atomic<size_t> error_count(0); |
290 | size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed); |
291 | if ((error_count_snapshot & (error_count_snapshot-1)) == 0) |
292 | syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " |
293 | "has hidden visibility or is defined in more than one translation " |
294 | "unit. They should all have public visibility. " |
295 | "%s, %s, %s.\n" , static_type->name(), dynamic_type->name(), |
296 | dst_type->name()); |
297 | // Redo the search comparing type_info's using strcmp |
298 | info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, |
299 | 0, 0, 0, false, false, false, true, nullptr}; |
300 | dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true); |
301 | } |
302 | #endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST |
303 | // Query the search. |
304 | switch (info.number_to_static_ptr) |
305 | { |
306 | case 0: |
307 | if (info.number_to_dst_ptr == 1 && |
308 | info.path_dynamic_ptr_to_static_ptr == public_path && |
309 | info.path_dynamic_ptr_to_dst_ptr == public_path) |
310 | return info.dst_ptr_not_leading_to_static_ptr; |
311 | break; |
312 | case 1: |
313 | if (info.path_dst_ptr_to_static_ptr == public_path || |
314 | ( |
315 | info.number_to_dst_ptr == 0 && |
316 | info.path_dynamic_ptr_to_static_ptr == public_path && |
317 | info.path_dynamic_ptr_to_dst_ptr == public_path |
318 | ) |
319 | ) |
320 | return info.dst_ptr_leading_to_static_ptr; |
321 | break; |
322 | } |
323 | |
324 | return nullptr; |
325 | } |
326 | |
327 | } // namespace |
328 | |
329 | // __shim_type_info |
330 | |
331 | __shim_type_info::~__shim_type_info() |
332 | { |
333 | } |
334 | |
335 | void __shim_type_info::noop1() const {} |
336 | void __shim_type_info::noop2() const {} |
337 | |
338 | // __fundamental_type_info |
339 | |
340 | // This miraculously (compiler magic) emits the type_info's for: |
341 | // 1. all of the fundamental types |
342 | // 2. pointers to all of the fundamental types |
343 | // 3. pointers to all of the const fundamental types |
344 | __fundamental_type_info::~__fundamental_type_info() |
345 | { |
346 | } |
347 | |
348 | // __array_type_info |
349 | |
350 | __array_type_info::~__array_type_info() |
351 | { |
352 | } |
353 | |
354 | // __function_type_info |
355 | |
356 | __function_type_info::~__function_type_info() |
357 | { |
358 | } |
359 | |
360 | // __enum_type_info |
361 | |
362 | __enum_type_info::~__enum_type_info() |
363 | { |
364 | } |
365 | |
366 | // __class_type_info |
367 | |
368 | __class_type_info::~__class_type_info() |
369 | { |
370 | } |
371 | |
372 | // __si_class_type_info |
373 | |
374 | __si_class_type_info::~__si_class_type_info() |
375 | { |
376 | } |
377 | |
378 | // __vmi_class_type_info |
379 | |
380 | __vmi_class_type_info::~__vmi_class_type_info() |
381 | { |
382 | } |
383 | |
384 | // __pbase_type_info |
385 | |
386 | __pbase_type_info::~__pbase_type_info() |
387 | { |
388 | } |
389 | |
390 | // __pointer_type_info |
391 | |
392 | __pointer_type_info::~__pointer_type_info() |
393 | { |
394 | } |
395 | |
396 | // __pointer_to_member_type_info |
397 | |
398 | __pointer_to_member_type_info::~__pointer_to_member_type_info() |
399 | { |
400 | } |
401 | |
402 | // can_catch |
403 | |
404 | // A handler is a match for an exception object of type E if |
405 | // 1. The handler is of type cv T or cv T& and E and T are the same type |
406 | // (ignoring the top-level cv-qualifiers), or |
407 | // 2. the handler is of type cv T or cv T& and T is an unambiguous public |
408 | // base class of E, or |
409 | // 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be |
410 | // converted to the type of the handler by either or both of |
411 | // A. a standard pointer conversion (4.10) not involving conversions to |
412 | // pointers to private or protected or ambiguous classes |
413 | // B. a qualification conversion |
414 | // 4. the handler is a pointer or pointer to member type and E is |
415 | // std::nullptr_t. |
416 | |
417 | // adjustedPtr: |
418 | // |
419 | // catch (A& a) : adjustedPtr == &a |
420 | // catch (A* a) : adjustedPtr == a |
421 | // catch (A** a) : adjustedPtr == a |
422 | // |
423 | // catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object) |
424 | // catch (D2* d2) : adjustedPtr == d2 |
425 | // catch (D2*& d2) : adjustedPtr == d2 |
426 | // |
427 | // catch (...) : adjustedPtr == & of the exception |
428 | // |
429 | // If the thrown type is nullptr_t and the caught type is a pointer to |
430 | // member type, adjustedPtr points to a statically-allocated null pointer |
431 | // representation of that type. |
432 | |
433 | // Handles bullet 1 |
434 | bool |
435 | __fundamental_type_info::can_catch(const __shim_type_info* thrown_type, |
436 | void*&) const |
437 | { |
438 | return is_equal(x: this, y: thrown_type, use_strcmp: false); |
439 | } |
440 | |
441 | bool |
442 | __array_type_info::can_catch(const __shim_type_info*, void*&) const |
443 | { |
444 | // We can get here if someone tries to catch an array by reference. |
445 | // However if someone tries to throw an array, it immediately gets |
446 | // converted to a pointer, which will not convert back to an array |
447 | // at the catch clause. So this can never catch anything. |
448 | return false; |
449 | } |
450 | |
451 | bool |
452 | __function_type_info::can_catch(const __shim_type_info*, void*&) const |
453 | { |
454 | // We can get here if someone tries to catch a function by reference. |
455 | // However if someone tries to throw a function, it immediately gets |
456 | // converted to a pointer, which will not convert back to a function |
457 | // at the catch clause. So this can never catch anything. |
458 | return false; |
459 | } |
460 | |
461 | // Handles bullet 1 |
462 | bool |
463 | __enum_type_info::can_catch(const __shim_type_info* thrown_type, |
464 | void*&) const |
465 | { |
466 | return is_equal(x: this, y: thrown_type, use_strcmp: false); |
467 | } |
468 | |
469 | #ifdef __clang__ |
470 | #pragma clang diagnostic push |
471 | #pragma clang diagnostic ignored "-Wmissing-field-initializers" |
472 | #endif |
473 | |
474 | // Handles bullets 1 and 2 |
475 | bool |
476 | __class_type_info::can_catch(const __shim_type_info* thrown_type, |
477 | void*& adjustedPtr) const |
478 | { |
479 | // bullet 1 |
480 | if (is_equal(x: this, y: thrown_type, use_strcmp: false)) |
481 | return true; |
482 | const __class_type_info* thrown_class_type = |
483 | dynamic_cast<const __class_type_info*>(thrown_type); |
484 | if (thrown_class_type == 0) |
485 | return false; |
486 | // bullet 2 |
487 | _LIBCXXABI_ASSERT(adjustedPtr, "catching a class without an object?" ); |
488 | __dynamic_cast_info info = {.dst_type: thrown_class_type, .static_ptr: 0, .static_type: this, .src2dst_offset: -1, .dst_ptr_leading_to_static_ptr: 0, .dst_ptr_not_leading_to_static_ptr: 0, .path_dst_ptr_to_static_ptr: 0, .path_dynamic_ptr_to_static_ptr: 0, .path_dynamic_ptr_to_dst_ptr: 0, .number_to_static_ptr: 0, .number_to_dst_ptr: 0, .is_dst_type_derived_from_static_type: 0, .number_of_dst_type: 0, .found_our_static_ptr: 0, .found_any_static_type: 0, .search_done: 0, .have_object: true, .vbase_cookie: nullptr}; |
489 | info.number_of_dst_type = 1; |
490 | thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); |
491 | if (info.path_dst_ptr_to_static_ptr == public_path) |
492 | { |
493 | adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr); |
494 | return true; |
495 | } |
496 | return false; |
497 | } |
498 | |
499 | #ifdef __clang__ |
500 | #pragma clang diagnostic pop |
501 | #endif |
502 | |
503 | // When we have an object to inspect - we just pass the pointer to the sub- |
504 | // object that matched the static_type we just checked. If that is different |
505 | // from any previously recorded pointer to that object type, then we have |
506 | // an ambiguous case. |
507 | |
508 | // When we have no object to inspect, we need to account for virtual bases |
509 | // explicitly. |
510 | // info->vbase_cookie is a pointer to the name of the innermost virtual base |
511 | // type, or nullptr if there is no virtual base on the path so far. |
512 | // adjustedPtr points to the subobject we just found. |
513 | // If vbase_cookie != any previously recorded (including the case of nullptr |
514 | // representing an already-found static sub-object) then we have an ambiguous |
515 | // case. Assuming that the vbase_cookie values agree; if then we have a |
516 | // different offset (adjustedPtr) from any previously recorded, this indicates |
517 | // an ambiguous case within the virtual base. |
518 | |
519 | void |
520 | __class_type_info::process_found_base_class(__dynamic_cast_info* info, |
521 | void* adjustedPtr, |
522 | int path_below) const |
523 | { |
524 | if (info->number_to_static_ptr == 0) { |
525 | // First time we found this base |
526 | info->dst_ptr_leading_to_static_ptr = adjustedPtr; |
527 | info->path_dst_ptr_to_static_ptr = path_below; |
528 | // stash the virtual base cookie. |
529 | info->dst_ptr_not_leading_to_static_ptr = info->vbase_cookie; |
530 | info->number_to_static_ptr = 1; |
531 | } else if (info->dst_ptr_not_leading_to_static_ptr == info->vbase_cookie && |
532 | info->dst_ptr_leading_to_static_ptr == adjustedPtr) { |
533 | // We've been here before. Update path to "most public" |
534 | if (info->path_dst_ptr_to_static_ptr == not_public_path) |
535 | info->path_dst_ptr_to_static_ptr = path_below; |
536 | } else { |
537 | // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr) |
538 | // to a static_type. |
539 | info->number_to_static_ptr += 1; |
540 | info->path_dst_ptr_to_static_ptr = not_public_path; |
541 | info->search_done = true; |
542 | } |
543 | } |
544 | |
545 | void |
546 | __class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, |
547 | void* adjustedPtr, |
548 | int path_below) const |
549 | { |
550 | if (is_equal(x: this, y: info->static_type, use_strcmp: false)) |
551 | process_found_base_class(info, adjustedPtr, path_below); |
552 | } |
553 | |
554 | void |
555 | __si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, |
556 | void* adjustedPtr, |
557 | int path_below) const |
558 | { |
559 | if (is_equal(x: this, y: info->static_type, use_strcmp: false)) |
560 | process_found_base_class(info, adjustedPtr, path_below); |
561 | else |
562 | __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below); |
563 | } |
564 | |
565 | void |
566 | __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, |
567 | void* adjustedPtr, |
568 | int path_below) const |
569 | { |
570 | bool is_virtual = __offset_flags & __virtual_mask; |
571 | ptrdiff_t offset_to_base = 0; |
572 | if (info->have_object) { |
573 | /* We have an object to inspect, we can look through its vtables to |
574 | find the layout. */ |
575 | offset_to_base = __offset_flags >> __offset_shift; |
576 | if (is_virtual) { |
577 | const char* vtable = strip_vtable(vtable: *static_cast<const char* const*>(adjustedPtr)); |
578 | offset_to_base = update_offset_to_base(vtable, offset_to_base); |
579 | } |
580 | } else if (!is_virtual) { |
581 | /* We have no object; however, for non-virtual bases, (since we do not |
582 | need to inspect any content) we can pretend to have an object based |
583 | at '0'. */ |
584 | offset_to_base = __offset_flags >> __offset_shift; |
585 | } else { |
586 | /* No object to inspect, and the next base is virtual. |
587 | We cannot indirect through the vtable to find the actual object offset. |
588 | So, update vbase_cookie to the new innermost virtual base using the |
589 | pointer to the typeinfo name as a key. */ |
590 | info->vbase_cookie = static_cast<const void*>(__base_type->name()); |
591 | // .. and reset the pointer. |
592 | adjustedPtr = nullptr; |
593 | } |
594 | __base_type->has_unambiguous_public_base( |
595 | info, adjustedPtr: reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(adjustedPtr) + offset_to_base), |
596 | path_below: (__offset_flags & __public_mask) ? path_below : not_public_path); |
597 | } |
598 | |
599 | void |
600 | __vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, |
601 | void* adjustedPtr, |
602 | int path_below) const |
603 | { |
604 | if (is_equal(x: this, y: info->static_type, use_strcmp: false)) |
605 | process_found_base_class(info, adjustedPtr, path_below); |
606 | else |
607 | { |
608 | typedef const __base_class_type_info* Iter; |
609 | const Iter e = __base_info + __base_count; |
610 | Iter p = __base_info; |
611 | p->has_unambiguous_public_base(info, adjustedPtr, path_below); |
612 | if (++p < e) |
613 | { |
614 | do |
615 | { |
616 | p->has_unambiguous_public_base(info, adjustedPtr, path_below); |
617 | if (info->search_done) |
618 | break; |
619 | } while (++p < e); |
620 | } |
621 | } |
622 | } |
623 | |
624 | // Handles bullet 1 for both pointers and member pointers |
625 | bool |
626 | __pbase_type_info::can_catch(const __shim_type_info* thrown_type, |
627 | void*&) const |
628 | { |
629 | bool use_strcmp = this->__flags & (__incomplete_class_mask | |
630 | __incomplete_mask); |
631 | if (!use_strcmp) { |
632 | const __pbase_type_info* thrown_pbase = dynamic_cast<const __pbase_type_info*>( |
633 | thrown_type); |
634 | if (!thrown_pbase) return false; |
635 | use_strcmp = thrown_pbase->__flags & (__incomplete_class_mask | |
636 | __incomplete_mask); |
637 | } |
638 | return is_equal(x: this, y: thrown_type, use_strcmp); |
639 | } |
640 | |
641 | #ifdef __clang__ |
642 | #pragma clang diagnostic push |
643 | #pragma clang diagnostic ignored "-Wmissing-field-initializers" |
644 | #endif |
645 | |
646 | // Handles bullets 1, 3 and 4 |
647 | // NOTE: It might not be safe to adjust the pointer if it is not not a pointer |
648 | // type. Only adjust the pointer after we know it is safe to do so. |
649 | bool |
650 | __pointer_type_info::can_catch(const __shim_type_info* thrown_type, |
651 | void*& adjustedPtr) const |
652 | { |
653 | // bullet 4 |
654 | if (is_equal(x: thrown_type, y: &typeid(std::nullptr_t), use_strcmp: false)) { |
655 | adjustedPtr = nullptr; |
656 | return true; |
657 | } |
658 | |
659 | // bullet 1 |
660 | if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) { |
661 | if (adjustedPtr != NULL) |
662 | adjustedPtr = *static_cast<void**>(adjustedPtr); |
663 | return true; |
664 | } |
665 | // bullet 3 |
666 | const __pointer_type_info* thrown_pointer_type = |
667 | dynamic_cast<const __pointer_type_info*>(thrown_type); |
668 | if (thrown_pointer_type == 0) |
669 | return false; |
670 | // Do the dereference adjustment |
671 | if (adjustedPtr != NULL) |
672 | adjustedPtr = *static_cast<void**>(adjustedPtr); |
673 | // bullet 3B and 3C |
674 | if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask) |
675 | return false; |
676 | if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask) |
677 | return false; |
678 | if (is_equal(x: __pointee, y: thrown_pointer_type->__pointee, use_strcmp: false)) |
679 | return true; |
680 | // bullet 3A |
681 | if (is_equal(x: __pointee, y: &typeid(void), use_strcmp: false)) { |
682 | // pointers to functions cannot be converted to void*. |
683 | // pointers to member functions are not handled here. |
684 | const __function_type_info* thrown_function = |
685 | dynamic_cast<const __function_type_info*>(thrown_pointer_type->__pointee); |
686 | return (thrown_function == nullptr); |
687 | } |
688 | // Handle pointer to pointer |
689 | const __pointer_type_info* nested_pointer_type = |
690 | dynamic_cast<const __pointer_type_info*>(__pointee); |
691 | if (nested_pointer_type) { |
692 | if (~__flags & __const_mask) return false; |
693 | return nested_pointer_type->can_catch_nested(thrown_pointer_type->__pointee); |
694 | } |
695 | |
696 | // Handle pointer to pointer to member |
697 | const __pointer_to_member_type_info* member_ptr_type = |
698 | dynamic_cast<const __pointer_to_member_type_info*>(__pointee); |
699 | if (member_ptr_type) { |
700 | if (~__flags & __const_mask) return false; |
701 | return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee); |
702 | } |
703 | |
704 | // Handle pointer to class type |
705 | const __class_type_info* catch_class_type = |
706 | dynamic_cast<const __class_type_info*>(__pointee); |
707 | if (catch_class_type == 0) |
708 | return false; |
709 | const __class_type_info* thrown_class_type = |
710 | dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee); |
711 | if (thrown_class_type == 0) |
712 | return false; |
713 | bool have_object = adjustedPtr != nullptr; |
714 | __dynamic_cast_info info = {.dst_type: thrown_class_type, .static_ptr: 0, .static_type: catch_class_type, .src2dst_offset: -1, .dst_ptr_leading_to_static_ptr: 0, .dst_ptr_not_leading_to_static_ptr: 0, .path_dst_ptr_to_static_ptr: 0, .path_dynamic_ptr_to_static_ptr: 0, .path_dynamic_ptr_to_dst_ptr: 0, .number_to_static_ptr: 0, .number_to_dst_ptr: 0, .is_dst_type_derived_from_static_type: 0, .number_of_dst_type: 0, .found_our_static_ptr: 0, .found_any_static_type: 0, .search_done: 0, |
715 | .have_object: have_object, .vbase_cookie: nullptr}; |
716 | info.number_of_dst_type = 1; |
717 | thrown_class_type->has_unambiguous_public_base(info: &info, adjustedPtr, path_below: public_path); |
718 | if (info.path_dst_ptr_to_static_ptr == public_path) |
719 | { |
720 | // In the case of a thrown null pointer, we have no object but we might |
721 | // well have computed the offset to where a public sub-object would be. |
722 | // However, we do not want to return that offset to the user; we still |
723 | // want them to catch a null ptr. |
724 | if (have_object) |
725 | adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr); |
726 | else |
727 | adjustedPtr = nullptr; |
728 | return true; |
729 | } |
730 | return false; |
731 | } |
732 | |
733 | bool __pointer_type_info::can_catch_nested( |
734 | const __shim_type_info* thrown_type) const |
735 | { |
736 | const __pointer_type_info* thrown_pointer_type = |
737 | dynamic_cast<const __pointer_type_info*>(thrown_type); |
738 | if (thrown_pointer_type == 0) |
739 | return false; |
740 | // bullet 3B |
741 | if (thrown_pointer_type->__flags & ~__flags) |
742 | return false; |
743 | if (is_equal(x: __pointee, y: thrown_pointer_type->__pointee, use_strcmp: false)) |
744 | return true; |
745 | // If the pointed to types differ then the catch type must be const |
746 | // qualified. |
747 | if (~__flags & __const_mask) |
748 | return false; |
749 | |
750 | // Handle pointer to pointer |
751 | const __pointer_type_info* nested_pointer_type = |
752 | dynamic_cast<const __pointer_type_info*>(__pointee); |
753 | if (nested_pointer_type) { |
754 | return nested_pointer_type->can_catch_nested( |
755 | thrown_type: thrown_pointer_type->__pointee); |
756 | } |
757 | |
758 | // Handle pointer to pointer to member |
759 | const __pointer_to_member_type_info* member_ptr_type = |
760 | dynamic_cast<const __pointer_to_member_type_info*>(__pointee); |
761 | if (member_ptr_type) { |
762 | return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee); |
763 | } |
764 | |
765 | return false; |
766 | } |
767 | |
768 | bool __pointer_to_member_type_info::can_catch( |
769 | const __shim_type_info* thrown_type, void*& adjustedPtr) const { |
770 | // bullet 4 |
771 | if (is_equal(x: thrown_type, y: &typeid(std::nullptr_t), use_strcmp: false)) { |
772 | // We assume that the pointer to member representation is the same for |
773 | // all pointers to data members and for all pointers to member functions. |
774 | struct X {}; |
775 | if (dynamic_cast<const __function_type_info*>(__pointee)) { |
776 | static int (X::*const null_ptr_rep)() = nullptr; |
777 | adjustedPtr = const_cast<int (X::**)()>(&null_ptr_rep); |
778 | } else { |
779 | static int X::*const null_ptr_rep = nullptr; |
780 | adjustedPtr = const_cast<int X::**>(&null_ptr_rep); |
781 | } |
782 | return true; |
783 | } |
784 | |
785 | // bullet 1 |
786 | if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) |
787 | return true; |
788 | |
789 | const __pointer_to_member_type_info* thrown_pointer_type = |
790 | dynamic_cast<const __pointer_to_member_type_info*>(thrown_type); |
791 | if (thrown_pointer_type == 0) |
792 | return false; |
793 | if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask) |
794 | return false; |
795 | if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask) |
796 | return false; |
797 | if (!is_equal(x: __pointee, y: thrown_pointer_type->__pointee, use_strcmp: false)) |
798 | return false; |
799 | if (is_equal(x: __context, y: thrown_pointer_type->__context, use_strcmp: false)) |
800 | return true; |
801 | |
802 | // [except.handle] does not allow the pointer-to-member conversions mentioned |
803 | // in [mem.conv] to take place. For this reason we don't check Derived->Base |
804 | // for Derived->Base conversions. |
805 | |
806 | return false; |
807 | } |
808 | |
809 | bool __pointer_to_member_type_info::can_catch_nested( |
810 | const __shim_type_info* thrown_type) const |
811 | { |
812 | const __pointer_to_member_type_info* thrown_member_ptr_type = |
813 | dynamic_cast<const __pointer_to_member_type_info*>(thrown_type); |
814 | if (thrown_member_ptr_type == 0) |
815 | return false; |
816 | if (~__flags & thrown_member_ptr_type->__flags) |
817 | return false; |
818 | if (!is_equal(x: __pointee, y: thrown_member_ptr_type->__pointee, use_strcmp: false)) |
819 | return false; |
820 | if (!is_equal(x: __context, y: thrown_member_ptr_type->__context, use_strcmp: false)) |
821 | return false; |
822 | return true; |
823 | } |
824 | |
825 | #ifdef __clang__ |
826 | #pragma clang diagnostic pop |
827 | #endif |
828 | |
829 | #ifdef __clang__ |
830 | #pragma clang diagnostic push |
831 | #pragma clang diagnostic ignored "-Wmissing-field-initializers" |
832 | #endif |
833 | |
834 | // __dynamic_cast |
835 | |
836 | // static_ptr: pointer to an object of type static_type; nonnull, and since the |
837 | // object is polymorphic, *(void**)static_ptr is a virtual table pointer. |
838 | // static_ptr is &v in the expression dynamic_cast<T>(v). |
839 | // static_type: static type of the object pointed to by static_ptr. |
840 | // dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)"). |
841 | // src2dst_offset: a static hint about the location of the |
842 | // source subobject with respect to the complete object; |
843 | // special negative values are: |
844 | // -1: no hint |
845 | // -2: static_type is not a public base of dst_type |
846 | // -3: static_type is a multiple public base type but never a |
847 | // virtual base type |
848 | // otherwise, the static_type type is a unique public nonvirtual |
849 | // base type of dst_type at offset src2dst_offset from the |
850 | // origin of dst_type. |
851 | // |
852 | // (dynamic_ptr, dynamic_type) are the run time type of the complete object |
853 | // referred to by static_ptr and a pointer to it. These can be found from |
854 | // static_ptr for polymorphic types. |
855 | // static_type is guaranteed to be a polymorphic type. |
856 | // |
857 | // (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each |
858 | // node of the tree represents a base class/object of its parent (or parents) below. |
859 | // Each node is uniquely represented by a pointer to the object, and a pointer |
860 | // to a type_info - its type. Different nodes may have the same pointer and |
861 | // different nodes may have the same type. But only one node has a specific |
862 | // (pointer-value, type) pair. In C++ two objects of the same type can not |
863 | // share the same address. |
864 | // |
865 | // There are two flavors of nodes which have the type dst_type: |
866 | // 1. Those that are derived from (below) (static_ptr, static_type). |
867 | // 2. Those that are not derived from (below) (static_ptr, static_type). |
868 | // |
869 | // Invariants of the DAG: |
870 | // |
871 | // There is at least one path from the root (dynamic_ptr, dynamic_type) to |
872 | // the node (static_ptr, static_type). This path may or may not be public. |
873 | // There may be more than one such path (some public some not). Such a path may |
874 | // or may not go through a node having type dst_type. |
875 | // |
876 | // No node of type T appears above a node of the same type. That means that |
877 | // there is only one node with dynamic_type. And if dynamic_type == dst_type, |
878 | // then there is only one dst_type in the DAG. |
879 | // |
880 | // No node of type dst_type appears above a node of type static_type. Such |
881 | // DAG's are possible in C++, but the compiler computes those dynamic_casts at |
882 | // compile time, and only calls __dynamic_cast when dst_type lies below |
883 | // static_type in the DAG. |
884 | // |
885 | // dst_type != static_type: The compiler computes the dynamic_cast in this case too. |
886 | // dynamic_type != static_type: The compiler computes the dynamic_cast in this case too. |
887 | // |
888 | // Returns: |
889 | // |
890 | // If there is exactly one dst_type of flavor 1, and |
891 | // If there is a public path from that dst_type to (static_ptr, static_type), or |
892 | // If there are 0 dst_types of flavor 2, and there is a public path from |
893 | // (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public |
894 | // path from (dynamic_ptr, dynamic_type) to the one dst_type, then return |
895 | // a pointer to that dst_type. |
896 | // Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and |
897 | // if there is a public path from (dynamic_ptr, dynamic_type) to |
898 | // (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type) |
899 | // to the one dst_type, then return a pointer to that one dst_type. |
900 | // Else return nullptr. |
901 | // |
902 | // If dynamic_type == dst_type, then the above algorithm collapses to the |
903 | // following cheaper algorithm: |
904 | // |
905 | // If there is a public path from (dynamic_ptr, dynamic_type) to |
906 | // (static_ptr, static_type), then return dynamic_ptr. |
907 | // Else return nullptr. |
908 | |
909 | extern "C" _LIBCXXABI_FUNC_VIS void * |
910 | __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, |
911 | const __class_type_info *dst_type, |
912 | std::ptrdiff_t src2dst_offset) { |
913 | // Get (dynamic_ptr, dynamic_type) from static_ptr |
914 | derived_object_info derived_info; |
915 | dyn_cast_get_derived_info(info: &derived_info, static_ptr); |
916 | |
917 | // Initialize answer to nullptr. This will be changed from the search |
918 | // results if a non-null answer is found. Regardless, this is what will |
919 | // be returned. |
920 | const void* dst_ptr = 0; |
921 | |
922 | // Find out if we can use a giant short cut in the search |
923 | if (is_equal(x: derived_info.dynamic_type, y: dst_type, use_strcmp: false)) |
924 | { |
925 | dst_ptr = dyn_cast_to_derived(static_ptr, |
926 | dynamic_ptr: derived_info.dynamic_ptr, |
927 | static_type, |
928 | dst_type, |
929 | offset_to_derived: derived_info.offset_to_derived, |
930 | src2dst_offset); |
931 | } |
932 | else |
933 | { |
934 | // Optimize toward downcasting: let's first try to do a downcast before |
935 | // falling back to the slow path. |
936 | dst_ptr = dyn_cast_try_downcast(static_ptr, |
937 | dynamic_ptr: derived_info.dynamic_ptr, |
938 | dst_type, |
939 | dynamic_type: derived_info.dynamic_type, |
940 | src2dst_offset); |
941 | |
942 | if (!dst_ptr) |
943 | { |
944 | dst_ptr = dyn_cast_slow(static_ptr, |
945 | dynamic_ptr: derived_info.dynamic_ptr, |
946 | static_type, |
947 | dst_type, |
948 | dynamic_type: derived_info.dynamic_type, |
949 | src2dst_offset); |
950 | } |
951 | } |
952 | |
953 | return const_cast<void*>(dst_ptr); |
954 | } |
955 | |
956 | #ifdef __clang__ |
957 | #pragma clang diagnostic pop |
958 | #endif |
959 | |
960 | // Call this function when you hit a static_type which is a base (above) a dst_type. |
961 | // Let caller know you hit a static_type. But only start recording details if |
962 | // this is (static_ptr, static_type) -- the node we are casting from. |
963 | // If this is (static_ptr, static_type) |
964 | // Record the path (public or not) from the dst_type to here. There may be |
965 | // multiple paths from the same dst_type to here, record the "most public" one. |
966 | // Record the dst_ptr as pointing to (static_ptr, static_type). |
967 | // If more than one (dst_ptr, dst_type) points to (static_ptr, static_type), |
968 | // then mark this dyanmic_cast as ambiguous and stop the search. |
969 | void |
970 | __class_type_info::process_static_type_above_dst(__dynamic_cast_info* info, |
971 | const void* dst_ptr, |
972 | const void* current_ptr, |
973 | int path_below) const |
974 | { |
975 | // Record that we found a static_type |
976 | info->found_any_static_type = true; |
977 | if (current_ptr == info->static_ptr) |
978 | { |
979 | // Record that we found (static_ptr, static_type) |
980 | info->found_our_static_ptr = true; |
981 | if (info->dst_ptr_leading_to_static_ptr == 0) |
982 | { |
983 | // First time here |
984 | info->dst_ptr_leading_to_static_ptr = dst_ptr; |
985 | info->path_dst_ptr_to_static_ptr = path_below; |
986 | info->number_to_static_ptr = 1; |
987 | // If there is only one dst_type in the entire tree and the path from |
988 | // there to here is public then we are done! |
989 | if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path) |
990 | info->search_done = true; |
991 | } |
992 | else if (info->dst_ptr_leading_to_static_ptr == dst_ptr) |
993 | { |
994 | // We've been here before. Update path to "most public" |
995 | if (info->path_dst_ptr_to_static_ptr == not_public_path) |
996 | info->path_dst_ptr_to_static_ptr = path_below; |
997 | // If there is only one dst_type in the entire tree and the path from |
998 | // there to here is public then we are done! |
999 | if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path) |
1000 | info->search_done = true; |
1001 | } |
1002 | else |
1003 | { |
1004 | // We've detected an ambiguous cast from (static_ptr, static_type) |
1005 | // to a dst_type |
1006 | info->number_to_static_ptr += 1; |
1007 | info->search_done = true; |
1008 | } |
1009 | } |
1010 | } |
1011 | |
1012 | // Call this function when you hit a static_type which is not a base (above) a dst_type. |
1013 | // If this is (static_ptr, static_type) |
1014 | // Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be |
1015 | // multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one. |
1016 | void |
1017 | __class_type_info::process_static_type_below_dst(__dynamic_cast_info* info, |
1018 | const void* current_ptr, |
1019 | int path_below) const |
1020 | { |
1021 | if (current_ptr == info->static_ptr) |
1022 | { |
1023 | // Record the most public path from (dynamic_ptr, dynamic_type) to |
1024 | // (static_ptr, static_type) |
1025 | if (info->path_dynamic_ptr_to_static_ptr != public_path) |
1026 | info->path_dynamic_ptr_to_static_ptr = path_below; |
1027 | } |
1028 | } |
1029 | |
1030 | // Call this function when searching below a dst_type node. This function searches |
1031 | // for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes. |
1032 | // If it finds a static_type node, there is no need to further search base classes |
1033 | // above. |
1034 | // If it finds a dst_type node it should search base classes using search_above_dst |
1035 | // to find out if this dst_type points to (static_ptr, static_type) or not. |
1036 | // Either way, the dst_type is recorded as one of two "flavors": one that does |
1037 | // or does not point to (static_ptr, static_type). |
1038 | // If this is neither a static_type nor a dst_type node, continue searching |
1039 | // base classes above. |
1040 | // All the hoopla surrounding the search code is doing nothing but looking for |
1041 | // excuses to stop the search prematurely (break out of the for-loop). That is, |
1042 | // the algorithm below is simply an optimization of this: |
1043 | // void |
1044 | // __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, |
1045 | // const void* current_ptr, |
1046 | // int path_below) const |
1047 | // { |
1048 | // typedef const __base_class_type_info* Iter; |
1049 | // if (this == info->static_type) |
1050 | // process_static_type_below_dst(info, current_ptr, path_below); |
1051 | // else if (this == info->dst_type) |
1052 | // { |
1053 | // // Record the most public access path that got us here |
1054 | // if (info->path_dynamic_ptr_to_dst_ptr != public_path) |
1055 | // info->path_dynamic_ptr_to_dst_ptr = path_below; |
1056 | // bool does_dst_type_point_to_our_static_type = false; |
1057 | // for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p) |
1058 | // { |
1059 | // p->search_above_dst(info, current_ptr, current_ptr, public_path); |
1060 | // if (info->found_our_static_ptr) |
1061 | // does_dst_type_point_to_our_static_type = true; |
1062 | // // break out early here if you can detect it doesn't matter if you do |
1063 | // } |
1064 | // if (!does_dst_type_point_to_our_static_type) |
1065 | // { |
1066 | // // We found a dst_type that doesn't point to (static_ptr, static_type) |
1067 | // // So record the address of this dst_ptr and increment the |
1068 | // // count of the number of such dst_types found in the tree. |
1069 | // info->dst_ptr_not_leading_to_static_ptr = current_ptr; |
1070 | // info->number_to_dst_ptr += 1; |
1071 | // } |
1072 | // } |
1073 | // else |
1074 | // { |
1075 | // // This is not a static_type and not a dst_type. |
1076 | // for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p) |
1077 | // { |
1078 | // p->search_below_dst(info, current_ptr, public_path); |
1079 | // // break out early here if you can detect it doesn't matter if you do |
1080 | // } |
1081 | // } |
1082 | // } |
1083 | void |
1084 | __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, |
1085 | const void* current_ptr, |
1086 | int path_below, |
1087 | bool use_strcmp) const |
1088 | { |
1089 | typedef const __base_class_type_info* Iter; |
1090 | if (is_equal(x: this, y: info->static_type, use_strcmp)) |
1091 | process_static_type_below_dst(info, current_ptr, path_below); |
1092 | else if (is_equal(x: this, y: 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 | bool does_dst_type_point_to_our_static_type = false; |
1111 | // Only search above here if dst_type derives from static_type, or |
1112 | // if it is unknown if dst_type derives from static_type. |
1113 | if (info->is_dst_type_derived_from_static_type != no) |
1114 | { |
1115 | // Set up flags to record results from all base classes |
1116 | bool is_dst_type_derived_from_static_type = false; |
1117 | |
1118 | // We've found a dst_type with a potentially public path to here. |
1119 | // We have to assume the path is public because it may become |
1120 | // public later (if we get back to here with a public path). |
1121 | // We can stop looking above if: |
1122 | // 1. We've found a public path to (static_ptr, static_type). |
1123 | // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type. |
1124 | // This is detected at the (static_ptr, static_type). |
1125 | // 3. We can prove that there is no public path to (static_ptr, static_type) |
1126 | // above here. |
1127 | const Iter e = __base_info + __base_count; |
1128 | for (Iter p = __base_info; p < e; ++p) |
1129 | { |
1130 | // Zero out found flags |
1131 | info->found_our_static_ptr = false; |
1132 | info->found_any_static_type = false; |
1133 | p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp); |
1134 | if (info->search_done) |
1135 | break; |
1136 | if (info->found_any_static_type) |
1137 | { |
1138 | is_dst_type_derived_from_static_type = true; |
1139 | if (info->found_our_static_ptr) |
1140 | { |
1141 | does_dst_type_point_to_our_static_type = true; |
1142 | // If we found what we're looking for, stop looking above. |
1143 | if (info->path_dst_ptr_to_static_ptr == public_path) |
1144 | break; |
1145 | // We found a private path to (static_ptr, static_type) |
1146 | // If there is no diamond then there is only one path |
1147 | // to (static_ptr, static_type) and we just found it. |
1148 | if (!(__flags & __diamond_shaped_mask)) |
1149 | break; |
1150 | } |
1151 | else |
1152 | { |
1153 | // If we found a static_type that isn't the one we're looking |
1154 | // for, and if there are no repeated types above here, |
1155 | // then stop looking. |
1156 | if (!(__flags & __non_diamond_repeat_mask)) |
1157 | break; |
1158 | } |
1159 | } |
1160 | } |
1161 | // If we found no static_type,s then dst_type doesn't derive |
1162 | // from static_type, else it does. Record this result so that |
1163 | // next time we hit a dst_type we will know not to search above |
1164 | // it if it doesn't derive from static_type. |
1165 | if (is_dst_type_derived_from_static_type) |
1166 | info->is_dst_type_derived_from_static_type = yes; |
1167 | else |
1168 | info->is_dst_type_derived_from_static_type = no; |
1169 | } |
1170 | if (!does_dst_type_point_to_our_static_type) |
1171 | { |
1172 | // We found a dst_type that doesn't point to (static_ptr, static_type) |
1173 | // So record the address of this dst_ptr and increment the |
1174 | // count of the number of such dst_types found in the tree. |
1175 | info->dst_ptr_not_leading_to_static_ptr = current_ptr; |
1176 | info->number_to_dst_ptr += 1; |
1177 | // If there exists another dst with a private path to |
1178 | // (static_ptr, static_type), then the cast from |
1179 | // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous, |
1180 | // so stop search. |
1181 | if (info->number_to_static_ptr == 1 && |
1182 | info->path_dst_ptr_to_static_ptr == not_public_path) |
1183 | info->search_done = true; |
1184 | } |
1185 | } |
1186 | } |
1187 | else |
1188 | { |
1189 | // This is not a static_type and not a dst_type. |
1190 | const Iter e = __base_info + __base_count; |
1191 | Iter p = __base_info; |
1192 | p->search_below_dst(info, current_ptr, path_below, use_strcmp); |
1193 | if (++p < e) |
1194 | { |
1195 | if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1) |
1196 | { |
1197 | // If there are multiple paths to a base above from here, or if |
1198 | // a dst_type pointing to (static_ptr, static_type) has been found, |
1199 | // then there is no way to break out of this loop early unless |
1200 | // something below detects the search is done. |
1201 | do |
1202 | { |
1203 | if (info->search_done) |
1204 | break; |
1205 | p->search_below_dst(info, current_ptr, path_below, use_strcmp); |
1206 | } while (++p < e); |
1207 | } |
1208 | else if (__flags & __non_diamond_repeat_mask) |
1209 | { |
1210 | // There are not multiple paths to any base class from here and a |
1211 | // dst_type pointing to (static_ptr, static_type) has not yet been |
1212 | // found. |
1213 | do |
1214 | { |
1215 | if (info->search_done) |
1216 | break; |
1217 | // If we just found a dst_type with a public path to (static_ptr, static_type), |
1218 | // then the only reason to continue the search is to make sure |
1219 | // no other dst_type points to (static_ptr, static_type). |
1220 | // If !diamond, then we don't need to search here. |
1221 | if (info->number_to_static_ptr == 1 && |
1222 | info->path_dst_ptr_to_static_ptr == public_path) |
1223 | break; |
1224 | p->search_below_dst(info, current_ptr, path_below, use_strcmp); |
1225 | } while (++p < e); |
1226 | } |
1227 | else |
1228 | { |
1229 | // There are no repeated types above this node. |
1230 | // There are no nodes with multiple parents above this node. |
1231 | // no dst_type has been found to (static_ptr, static_type) |
1232 | do |
1233 | { |
1234 | if (info->search_done) |
1235 | break; |
1236 | // If we just found a dst_type with a public path to (static_ptr, static_type), |
1237 | // then the only reason to continue the search is to make sure |
1238 | // no other dst_type points to (static_ptr, static_type). |
1239 | // If !diamond, then we don't need to search here. |
1240 | // if we just found a dst_type with a private path to (static_ptr, static_type), |
1241 | // then we're only looking for a public path to (static_ptr, static_type) |
1242 | // and to check for other dst_types. |
1243 | // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type) |
1244 | // and not a dst_type under here. |
1245 | if (info->number_to_static_ptr == 1) |
1246 | break; |
1247 | p->search_below_dst(info, current_ptr, path_below, use_strcmp); |
1248 | } while (++p < e); |
1249 | } |
1250 | } |
1251 | } |
1252 | } |
1253 | |
1254 | // This is the same algorithm as __vmi_class_type_info::search_below_dst but |
1255 | // simplified to the case that there is only a single base class. |
1256 | void |
1257 | __si_class_type_info::search_below_dst(__dynamic_cast_info* info, |
1258 | const void* current_ptr, |
1259 | int path_below, |
1260 | bool use_strcmp) const |
1261 | { |
1262 | if (is_equal(x: this, y: info->static_type, use_strcmp)) |
1263 | process_static_type_below_dst(info, current_ptr, path_below); |
1264 | else if (is_equal(x: this, y: info->dst_type, use_strcmp)) |
1265 | { |
1266 | // We've been here before if we've recorded current_ptr in one of these |
1267 | // two places: |
1268 | if (current_ptr == info->dst_ptr_leading_to_static_ptr || |
1269 | current_ptr == info->dst_ptr_not_leading_to_static_ptr) |
1270 | { |
1271 | // We've seen this node before, and therefore have already searched |
1272 | // its base classes above. |
1273 | // Update path to here that is "most public". |
1274 | if (path_below == public_path) |
1275 | info->path_dynamic_ptr_to_dst_ptr = public_path; |
1276 | } |
1277 | else // We have haven't been here before |
1278 | { |
1279 | // Record the access path that got us here |
1280 | // If there is more than one dst_type this path doesn't matter. |
1281 | info->path_dynamic_ptr_to_dst_ptr = path_below; |
1282 | bool does_dst_type_point_to_our_static_type = false; |
1283 | // Only search above here if dst_type derives from static_type, or |
1284 | // if it is unknown if dst_type derives from static_type. |
1285 | if (info->is_dst_type_derived_from_static_type != no) |
1286 | { |
1287 | // Set up flags to record results from all base classes |
1288 | bool is_dst_type_derived_from_static_type = false; |
1289 | // Zero out found flags |
1290 | info->found_our_static_ptr = false; |
1291 | info->found_any_static_type = false; |
1292 | __base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp); |
1293 | if (info->found_any_static_type) |
1294 | { |
1295 | is_dst_type_derived_from_static_type = true; |
1296 | if (info->found_our_static_ptr) |
1297 | does_dst_type_point_to_our_static_type = true; |
1298 | } |
1299 | // If we found no static_type,s then dst_type doesn't derive |
1300 | // from static_type, else it does. Record this result so that |
1301 | // next time we hit a dst_type we will know not to search above |
1302 | // it if it doesn't derive from static_type. |
1303 | if (is_dst_type_derived_from_static_type) |
1304 | info->is_dst_type_derived_from_static_type = yes; |
1305 | else |
1306 | info->is_dst_type_derived_from_static_type = no; |
1307 | } |
1308 | if (!does_dst_type_point_to_our_static_type) |
1309 | { |
1310 | // We found a dst_type that doesn't point to (static_ptr, static_type) |
1311 | // So record the address of this dst_ptr and increment the |
1312 | // count of the number of such dst_types found in the tree. |
1313 | info->dst_ptr_not_leading_to_static_ptr = current_ptr; |
1314 | info->number_to_dst_ptr += 1; |
1315 | // If there exists another dst with a private path to |
1316 | // (static_ptr, static_type), then the cast from |
1317 | // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous. |
1318 | if (info->number_to_static_ptr == 1 && |
1319 | info->path_dst_ptr_to_static_ptr == not_public_path) |
1320 | info->search_done = true; |
1321 | } |
1322 | } |
1323 | } |
1324 | else |
1325 | { |
1326 | // This is not a static_type and not a dst_type |
1327 | __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp); |
1328 | } |
1329 | } |
1330 | |
1331 | // This is the same algorithm as __vmi_class_type_info::search_below_dst but |
1332 | // simplified to the case that there is no base class. |
1333 | void |
1334 | __class_type_info::search_below_dst(__dynamic_cast_info* info, |
1335 | const void* current_ptr, |
1336 | int path_below, |
1337 | bool use_strcmp) const |
1338 | { |
1339 | if (is_equal(x: this, y: info->static_type, use_strcmp)) |
1340 | process_static_type_below_dst(info, current_ptr, path_below); |
1341 | else if (is_equal(x: this, y: info->dst_type, use_strcmp)) |
1342 | { |
1343 | // We've been here before if we've recorded current_ptr in one of these |
1344 | // two places: |
1345 | if (current_ptr == info->dst_ptr_leading_to_static_ptr || |
1346 | current_ptr == info->dst_ptr_not_leading_to_static_ptr) |
1347 | { |
1348 | // We've seen this node before, and therefore have already searched |
1349 | // its base classes above. |
1350 | // Update path to here that is "most public". |
1351 | if (path_below == public_path) |
1352 | info->path_dynamic_ptr_to_dst_ptr = public_path; |
1353 | } |
1354 | else // We have haven't been here before |
1355 | { |
1356 | // Record the access path that got us here |
1357 | // If there is more than one dst_type this path doesn't matter. |
1358 | info->path_dynamic_ptr_to_dst_ptr = path_below; |
1359 | // We found a dst_type that doesn't point to (static_ptr, static_type) |
1360 | // So record the address of this dst_ptr and increment the |
1361 | // count of the number of such dst_types found in the tree. |
1362 | info->dst_ptr_not_leading_to_static_ptr = current_ptr; |
1363 | info->number_to_dst_ptr += 1; |
1364 | // If there exists another dst with a private path to |
1365 | // (static_ptr, static_type), then the cast from |
1366 | // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous. |
1367 | if (info->number_to_static_ptr == 1 && |
1368 | info->path_dst_ptr_to_static_ptr == not_public_path) |
1369 | info->search_done = true; |
1370 | // We found that dst_type does not derive from static_type |
1371 | info->is_dst_type_derived_from_static_type = no; |
1372 | } |
1373 | } |
1374 | } |
1375 | |
1376 | // Call this function when searching above a dst_type node. This function searches |
1377 | // for a public path to (static_ptr, static_type). |
1378 | // This function is guaranteed not to find a node of type dst_type. |
1379 | // Theoretically this is a very simple function which just stops if it finds a |
1380 | // static_type node: All the hoopla surrounding the search code is doing |
1381 | // nothing but looking for excuses to stop the search prematurely (break out of |
1382 | // the for-loop). That is, the algorithm below is simply an optimization of this: |
1383 | // void |
1384 | // __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, |
1385 | // const void* dst_ptr, |
1386 | // const void* current_ptr, |
1387 | // int path_below) const |
1388 | // { |
1389 | // if (this == info->static_type) |
1390 | // process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); |
1391 | // else |
1392 | // { |
1393 | // typedef const __base_class_type_info* Iter; |
1394 | // // This is not a static_type and not a dst_type |
1395 | // for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p) |
1396 | // { |
1397 | // p->search_above_dst(info, dst_ptr, current_ptr, public_path); |
1398 | // // break out early here if you can detect it doesn't matter if you do |
1399 | // } |
1400 | // } |
1401 | // } |
1402 | void |
1403 | __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, |
1404 | const void* dst_ptr, |
1405 | const void* current_ptr, |
1406 | int path_below, |
1407 | bool use_strcmp) const |
1408 | { |
1409 | if (is_equal(x: this, y: info->static_type, use_strcmp)) |
1410 | process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); |
1411 | else |
1412 | { |
1413 | typedef const __base_class_type_info* Iter; |
1414 | // This is not a static_type and not a dst_type |
1415 | // Save flags so they can be restored when returning to nodes below. |
1416 | bool found_our_static_ptr = info->found_our_static_ptr; |
1417 | bool found_any_static_type = info->found_any_static_type; |
1418 | // We've found a dst_type below with a path to here. If the path |
1419 | // to here is not public, there may be another path to here that |
1420 | // is public. So we have to assume that the path to here is public. |
1421 | // We can stop looking above if: |
1422 | // 1. We've found a public path to (static_ptr, static_type). |
1423 | // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type. |
1424 | // This is detected at the (static_ptr, static_type). |
1425 | // 3. We can prove that there is no public path to (static_ptr, static_type) |
1426 | // above here. |
1427 | const Iter e = __base_info + __base_count; |
1428 | Iter p = __base_info; |
1429 | // Zero out found flags |
1430 | info->found_our_static_ptr = false; |
1431 | info->found_any_static_type = false; |
1432 | p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp); |
1433 | found_our_static_ptr |= info->found_our_static_ptr; |
1434 | found_any_static_type |= info->found_any_static_type; |
1435 | if (++p < e) |
1436 | { |
1437 | do |
1438 | { |
1439 | if (info->search_done) |
1440 | break; |
1441 | if (info->found_our_static_ptr) |
1442 | { |
1443 | // If we found what we're looking for, stop looking above. |
1444 | if (info->path_dst_ptr_to_static_ptr == public_path) |
1445 | break; |
1446 | // We found a private path to (static_ptr, static_type) |
1447 | // If there is no diamond then there is only one path |
1448 | // to (static_ptr, static_type) from here and we just found it. |
1449 | if (!(__flags & __diamond_shaped_mask)) |
1450 | break; |
1451 | } |
1452 | else if (info->found_any_static_type) |
1453 | { |
1454 | // If we found a static_type that isn't the one we're looking |
1455 | // for, and if there are no repeated types above here, |
1456 | // then stop looking. |
1457 | if (!(__flags & __non_diamond_repeat_mask)) |
1458 | break; |
1459 | } |
1460 | // Zero out found flags |
1461 | info->found_our_static_ptr = false; |
1462 | info->found_any_static_type = false; |
1463 | p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp); |
1464 | found_our_static_ptr |= info->found_our_static_ptr; |
1465 | found_any_static_type |= info->found_any_static_type; |
1466 | } while (++p < e); |
1467 | } |
1468 | // Restore flags |
1469 | info->found_our_static_ptr = found_our_static_ptr; |
1470 | info->found_any_static_type = found_any_static_type; |
1471 | } |
1472 | } |
1473 | |
1474 | // This is the same algorithm as __vmi_class_type_info::search_above_dst but |
1475 | // simplified to the case that there is only a single base class. |
1476 | void |
1477 | __si_class_type_info::search_above_dst(__dynamic_cast_info* info, |
1478 | const void* dst_ptr, |
1479 | const void* current_ptr, |
1480 | int path_below, |
1481 | bool use_strcmp) const |
1482 | { |
1483 | if (is_equal(x: this, y: info->static_type, use_strcmp)) |
1484 | process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); |
1485 | else |
1486 | __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp); |
1487 | } |
1488 | |
1489 | // This is the same algorithm as __vmi_class_type_info::search_above_dst but |
1490 | // simplified to the case that there is no base class. |
1491 | void |
1492 | __class_type_info::search_above_dst(__dynamic_cast_info* info, |
1493 | const void* dst_ptr, |
1494 | const void* current_ptr, |
1495 | int path_below, |
1496 | bool use_strcmp) const |
1497 | { |
1498 | if (is_equal(x: this, y: info->static_type, use_strcmp)) |
1499 | process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); |
1500 | } |
1501 | |
1502 | // The search functions for __base_class_type_info are simply convenience |
1503 | // functions for adjusting the current_ptr and path_below as the search is |
1504 | // passed up to the base class node. |
1505 | |
1506 | void |
1507 | __base_class_type_info::search_above_dst(__dynamic_cast_info* info, |
1508 | const void* dst_ptr, |
1509 | const void* current_ptr, |
1510 | int path_below, |
1511 | bool use_strcmp) const |
1512 | { |
1513 | ptrdiff_t offset_to_base = __offset_flags >> __offset_shift; |
1514 | if (__offset_flags & __virtual_mask) |
1515 | { |
1516 | const char* vtable = strip_vtable(vtable: *static_cast<const char* const*>(current_ptr)); |
1517 | offset_to_base = update_offset_to_base(vtable, offset_to_base); |
1518 | } |
1519 | __base_type->search_above_dst(info, dst_ptr, |
1520 | current_ptr: static_cast<const char*>(current_ptr) + offset_to_base, |
1521 | path_below: (__offset_flags & __public_mask) ? |
1522 | path_below : |
1523 | not_public_path, |
1524 | use_strcmp); |
1525 | } |
1526 | |
1527 | void |
1528 | __base_class_type_info::search_below_dst(__dynamic_cast_info* info, |
1529 | const void* current_ptr, |
1530 | int path_below, |
1531 | bool use_strcmp) const |
1532 | { |
1533 | ptrdiff_t offset_to_base = __offset_flags >> __offset_shift; |
1534 | if (__offset_flags & __virtual_mask) |
1535 | { |
1536 | const char* vtable = strip_vtable(vtable: *static_cast<const char* const*>(current_ptr)); |
1537 | offset_to_base = update_offset_to_base(vtable, offset_to_base); |
1538 | } |
1539 | __base_type->search_below_dst(info, |
1540 | current_ptr: static_cast<const char*>(current_ptr) + offset_to_base, |
1541 | path_below: (__offset_flags & __public_mask) ? |
1542 | path_below : |
1543 | not_public_path, |
1544 | use_strcmp); |
1545 | } |
1546 | |
1547 | } // __cxxabiv1 |
1548 | |