Changeset View
Changeset View
Standalone View
Standalone View
src/private_typeinfo.cpp
//===----------------------- private_typeinfo.cpp -------------------------===// | //===----------------------- private_typeinfo.cpp -------------------------===// | ||||
// | // | ||||
// The LLVM Compiler Infrastructure | // The LLVM Compiler Infrastructure | ||||
// | // | ||||
// This file is dual licensed under the MIT and the University of Illinois Open | // This file is dual licensed under the MIT and the University of Illinois Open | ||||
// Source Licenses. See LICENSE.TXT for details. | // Source Licenses. See LICENSE.TXT for details. | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
#include "private_typeinfo.h" | #include "private_typeinfo.h" | ||||
// The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more | // The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more | ||||
// forgiving when type_info's mistakenly have hidden visibility and thus | // forgiving when multiple type_infos exist for a single type. This happens if | ||||
// multiple type_infos can exist for a single type. | // the libraries are mistakenly built with the type_infos having hidden | ||||
// visibility, but also occurs when the libraries are loaded with dlopen. | |||||
// | // | ||||
// When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where | // When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where | ||||
// there is a detected inconsistency in the type_info hierarchy during a | // there is a detected inconsistency in the type_info hierarchy during a | ||||
// dynamic_cast, then the equality operation will fall back to using strcmp | // dynamic_cast, then the equality operation will fall back to using strcmp | ||||
// on type_info names to determine type_info equality. | // on type_info names to determine type_info equality. | ||||
// | // | ||||
// This change happens *only* under dynamic_cast, and only when | |||||
// dynamic_cast is faced with the choice: abort, or possibly give back the | |||||
// wrong answer. If when the dynamic_cast is done with this fallback | |||||
// algorithm and an inconsistency is still detected, dynamic_cast will call | |||||
// abort with an appropriate message. | |||||
// | |||||
// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a | |||||
// printf-like function called syslog: | |||||
// | |||||
// void syslog(int facility_priority, const char* format, ...); | |||||
// | |||||
// If you want this functionality but your platform doesn't have syslog, | |||||
// just implement it in terms of fprintf(stderr, ...). | |||||
// | |||||
// _LIBCXX_DYNAMIC_FALLBACK is currently off by default. | // _LIBCXX_DYNAMIC_FALLBACK is currently off by default. | ||||
#include <string.h> | #include <string.h> | ||||
#ifdef _LIBCXX_DYNAMIC_FALLBACK | |||||
#include "abort_message.h" | |||||
#include <sys/syslog.h> | |||||
#endif | |||||
// On Windows, typeids are different between DLLs and EXEs, so comparing | // On Windows, typeids are different between DLLs and EXEs, so comparing | ||||
// type_info* will work for typeids from the same compiled file but fail | // type_info* will work for typeids from the same compiled file but fail | ||||
// for typeids from a DLL and an executable. Among other things, exceptions | // for typeids from a DLL and an executable. Among other things, exceptions | ||||
// are not caught by handlers since can_catch() returns false. | // are not caught by handlers since can_catch() returns false. | ||||
// | // | ||||
// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls | // Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls | ||||
// is_equal() with use_strcmp=false so the string names are not compared. | // is_equal() with use_strcmp=false so the string names are not compared. | ||||
▲ Show 20 Lines • Show All 588 Lines • ▼ Show 20 Lines | if (is_equal(dynamic_type, dst_type, false)) | ||||
info.number_of_dst_type = 1; | info.number_of_dst_type = 1; | ||||
// Do the search | // Do the search | ||||
dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false); | dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false); | ||||
#ifdef _LIBCXX_DYNAMIC_FALLBACK | #ifdef _LIBCXX_DYNAMIC_FALLBACK | ||||
// The following if should always be false because we should definitely | // The following if should always be false because we should definitely | ||||
// find (static_ptr, static_type), either on a public or private path | // find (static_ptr, static_type), either on a public or private path | ||||
if (info.path_dst_ptr_to_static_ptr == unknown) | if (info.path_dst_ptr_to_static_ptr == unknown) | ||||
{ | { | ||||
// We get here only if there is some kind of visibility problem | // We get here only if there is some kind of visibility problem in | ||||
// in client code. | // client code. Possibly because the binaries were built | ||||
syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " | // incorrectly, but possibly because the library was loaded with | ||||
"should have public visibility. At least one of them is hidden. %s" | // dlopen. | ||||
", %s.\n", static_type->name(), dynamic_type->name()); | // | ||||
// Redo the search comparing type_info's using strcmp | // Redo the search comparing type_info's using strcmp | ||||
info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; | info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; | ||||
info.number_of_dst_type = 1; | info.number_of_dst_type = 1; | ||||
dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true); | dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true); | ||||
} | } | ||||
#endif // _LIBCXX_DYNAMIC_FALLBACK | #endif // _LIBCXX_DYNAMIC_FALLBACK | ||||
// Query the search. | // Query the search. | ||||
if (info.path_dst_ptr_to_static_ptr == public_path) | if (info.path_dst_ptr_to_static_ptr == public_path) | ||||
dst_ptr = dynamic_ptr; | dst_ptr = dynamic_ptr; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Not using giant short cut. Do the search | // Not using giant short cut. Do the search | ||||
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false); | dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false); | ||||
#ifdef _LIBCXX_DYNAMIC_FALLBACK | #ifdef _LIBCXX_DYNAMIC_FALLBACK | ||||
// The following if should always be false because we should definitely | // The following if should always be false because we should definitely | ||||
// find (static_ptr, static_type), either on a public or private path | // find (static_ptr, static_type), either on a public or private path | ||||
if (info.path_dst_ptr_to_static_ptr == unknown && | if (info.path_dst_ptr_to_static_ptr == unknown && | ||||
info.path_dynamic_ptr_to_static_ptr == unknown) | info.path_dynamic_ptr_to_static_ptr == unknown) | ||||
{ | { | ||||
syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " | |||||
" has hidden visibility. They should all have public visibility. " | |||||
" %s, %s, %s.\n", static_type->name(), dynamic_type->name(), | |||||
dst_type->name()); | |||||
// Redo the search comparing type_info's using strcmp | // Redo the search comparing type_info's using strcmp | ||||
info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; | info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; | ||||
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true); | dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true); | ||||
} | } | ||||
#endif // _LIBCXX_DYNAMIC_FALLBACK | #endif // _LIBCXX_DYNAMIC_FALLBACK | ||||
// Query the search. | // Query the search. | ||||
switch (info.number_to_static_ptr) | switch (info.number_to_static_ptr) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 608 Lines • Show Last 20 Lines |