[cfe-commits] [libcxxabi] r164863 - in /libcxxabi/trunk/src: private_typeinfo.cpp private_typeinfo.h

Howard Hinnant hhinnant at apple.com
Fri Sep 28 15:43:50 PDT 2012


Author: hhinnant
Date: Fri Sep 28 17:43:50 2012
New Revision: 164863

URL: http://llvm.org/viewvc/llvm-project?rev=164863&view=rev
Log:
Set up code under _LIBCXX_DYNAMIC_FALLBACK which is off by default.  For a full description of _LIBCXX_DYNAMIC_FALLBACK, see src/private_typeinfo.cpp.

Modified:
    libcxxabi/trunk/src/private_typeinfo.cpp
    libcxxabi/trunk/src/private_typeinfo.h

Modified: libcxxabi/trunk/src/private_typeinfo.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.cpp?rev=164863&r1=164862&r2=164863&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.cpp (original)
+++ libcxxabi/trunk/src/private_typeinfo.cpp Fri Sep 28 17:43:50 2012
@@ -9,7 +9,34 @@
 
 #include "private_typeinfo.h"
 
-#if __APPLE__
+// The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more
+// forgiving when type_info's mistakenly have hidden visibility and thus
+// multiple type_infos can exist for a single type.
+// 
+// When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where
+// there is a detected inconsistency in the type_info hierarchy during a
+// dynamic_cast, then the equality operation will fall back to using strcmp
+// on type_info names to determin 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 approriate message.
+// 
+// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a
+// printf-like function called syslog:
+// 
+//     void syslog(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.
+
+#if _LIBCXX_DYNAMIC_FALLBACK
+#include "abort_message.h"
+#include <string.h>
 #include <sys/syslog.h>
 #endif
 
@@ -18,6 +45,28 @@
 
 #pragma GCC visibility push(hidden)
 
+#if _LIBCXX_DYNAMIC_FALLBACK
+
+inline
+bool
+is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp)
+{
+    if (!use_strcmp)
+        return x == y;
+    return strcmp(x->name(), y->name()) == 0;
+}
+
+#else  // !_LIBCXX_DYNAMIC_FALLBACK
+
+inline
+bool
+is_equal(const std::type_info* x, const std::type_info* y, bool)
+{
+    return x == y;
+}
+
+#endif  // _LIBCXX_DYNAMIC_FALLBACK
+
 // __shim_type_info
 
 __shim_type_info::~__shim_type_info()
@@ -440,8 +489,8 @@
         // Using giant short cut.  Add that information to info.
         info.number_of_dst_type = 1;
         // Do the  search
-        dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path);
-#if __APPLE__
+        dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
+#if _LIBCXX_DYNAMIC_FALLBACK
         // The following if should always be false because we should definitely
         //   find (static_ptr, static_type), either on a public or private path
         if (info.path_dst_ptr_to_static_ptr == unknown)
@@ -451,9 +500,18 @@
             syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
                     "should have public visibility.  At least of of them is hidden. %s" 
                     ", %s.\n", static_type->name(), dynamic_type->name());
-            info.path_dst_ptr_to_static_ptr = public_path;
+            // Redo the search comparing type_info's using strcmp
+            info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
+            info.number_of_dst_type = 1;
+            dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
+            if (info.path_dst_ptr_to_static_ptr == unknown)
+            {
+                abort_message("dynamic_cast error: Unable to compute dynamic "
+                              "cast from %s to %s\n", static_type->name(),
+                              dynamic_type->name());
+            }
         }
-#endif  // __APPLE__
+#endif  // _LIBCXX_DYNAMIC_FALLBACK
         // Query the search.
         if (info.path_dst_ptr_to_static_ptr == public_path)
             dst_ptr = dynamic_ptr;
@@ -461,19 +519,30 @@
     else
     {
         // Not using giant short cut.  Do the search
-        dynamic_type->search_below_dst(&info, dynamic_ptr, public_path);
- #if __APPLE__
+        dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
+ #if _LIBCXX_DYNAMIC_FALLBACK
         // The following if should always be false because we should definitely
         //   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)
         {
             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
+            info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
+            dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
+            if (info.path_dst_ptr_to_static_ptr == unknown &&
+                info.path_dynamic_ptr_to_static_ptr == unknown)
+            {
+                abort_message("dynamic_cast error: Unable to compute dynamic "
+                              "cast from %s to %s with a dynamic type of %s\n",
+                              static_type->name(), dst_type->name(),
+                              dynamic_type->name());
+            }
         }
-#endif  // __APPLE__
+#endif  // _LIBCXX_DYNAMIC_FALLBACK
         // Query the search.
         switch (info.number_to_static_ptr)
         {
@@ -629,12 +698,13 @@
 void
 __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
                                         const void* current_ptr,
-                                        int path_below) const
+                                        int path_below,
+                                        bool use_strcmp) const
 {
     typedef const __base_class_type_info* Iter;
-    if (this == info->static_type)
+    if (is_equal(this, info->static_type, use_strcmp))
         process_static_type_below_dst(info, current_ptr, path_below);
-    else if (this == info->dst_type)
+    else if (is_equal(this, info->dst_type, use_strcmp))
     {
         // We've been here before if we've recorded current_ptr in one of these
         //   two places:
@@ -674,7 +744,7 @@
                     // Zero out found flags
                     info->found_our_static_ptr = false;
                     info->found_any_static_type = false;
-                    p->search_above_dst(info, current_ptr, current_ptr, public_path);
+                    p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
                     if (info->search_done)
                         break;
                     if (info->found_any_static_type)
@@ -733,7 +803,7 @@
         // This is not a static_type and not a dst_type.
         const Iter e = __base_info + __base_count;
         Iter p = __base_info;
-        p->search_below_dst(info, current_ptr, path_below);
+        p->search_below_dst(info, current_ptr, path_below, use_strcmp);
         if (++p < e)
         {
             if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)
@@ -746,7 +816,7 @@
                 {
                     if (info->search_done)
                         break;
-                    p->search_below_dst(info, current_ptr, path_below);
+                    p->search_below_dst(info, current_ptr, path_below, use_strcmp);
                 } while (++p < e);
             }
             else if (__flags & __non_diamond_repeat_mask)
@@ -765,7 +835,7 @@
                     if (info->number_to_static_ptr == 1 &&
                               info->path_dst_ptr_to_static_ptr == public_path)
                         break;
-                    p->search_below_dst(info, current_ptr, path_below);
+                    p->search_below_dst(info, current_ptr, path_below, use_strcmp);
                 } while (++p < e);
             }
             else
@@ -788,7 +858,7 @@
                     //    and not a dst_type under here.
                     if (info->number_to_static_ptr == 1)
                         break;
-                    p->search_below_dst(info, current_ptr, path_below);
+                    p->search_below_dst(info, current_ptr, path_below, use_strcmp);
                 } while (++p < e);
             }
         }
@@ -800,11 +870,12 @@
 void
 __si_class_type_info::search_below_dst(__dynamic_cast_info* info,
                                        const void* current_ptr,
-                                       int path_below) const
+                                       int path_below,
+                                       bool use_strcmp) const
 {
-    if (this == info->static_type)
+    if (is_equal(this, info->static_type, use_strcmp))
         process_static_type_below_dst(info, current_ptr, path_below);
-    else if (this == info->dst_type)
+    else if (is_equal(this, info->dst_type, use_strcmp))
     {
         // We've been here before if we've recorded current_ptr in one of these
         //   two places:
@@ -832,7 +903,7 @@
                 // Zero out found flags
                 info->found_our_static_ptr = false;
                 info->found_any_static_type = false;
-                __base_type->search_above_dst(info, current_ptr, current_ptr, public_path);
+                __base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
                 if (info->found_any_static_type)
                 {
                     is_dst_type_derived_from_static_type = true;
@@ -867,7 +938,7 @@
     else
     {
         // This is not a static_type and not a dst_type
-        __base_type->search_below_dst(info, current_ptr, path_below);
+        __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp);
     }
 }
 
@@ -876,12 +947,13 @@
 void
 __class_type_info::search_below_dst(__dynamic_cast_info* info,
                                     const void* current_ptr,
-                                    int path_below) const
+                                    int path_below,
+                                    bool use_strcmp) const
 {
     typedef const __base_class_type_info* Iter;
-    if (this == info->static_type)
+    if (is_equal(this, info->static_type, use_strcmp))
         process_static_type_below_dst(info, current_ptr, path_below);
-    else if (this == info->dst_type)
+    else if (is_equal(this, info->dst_type, use_strcmp))
     {
         // We've been here before if we've recorded current_ptr in one of these
         //   two places:
@@ -946,9 +1018,10 @@
 __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
                                         const void* dst_ptr,
                                         const void* current_ptr,
-                                        int path_below) const
+                                        int path_below,
+                                        bool use_strcmp) const
 {
-    if (this == info->static_type)
+    if (is_equal(this, info->static_type, use_strcmp))
         process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
     else
     {
@@ -971,7 +1044,7 @@
         // Zero out found flags
         info->found_our_static_ptr = false;
         info->found_any_static_type = false;
-        p->search_above_dst(info, dst_ptr, current_ptr, path_below);
+        p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
         if (++p < e)
         {
             do
@@ -1000,7 +1073,7 @@
                 // Zero out found flags
                 info->found_our_static_ptr = false;
                 info->found_any_static_type = false;
-                p->search_above_dst(info, dst_ptr, current_ptr, path_below);
+                p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
             } while (++p < e);
         }
         // Restore flags
@@ -1015,12 +1088,13 @@
 __si_class_type_info::search_above_dst(__dynamic_cast_info* info,
                                        const void* dst_ptr,
                                        const void* current_ptr,
-                                       int path_below) const
+                                       int path_below,
+                                       bool use_strcmp) const
 {
-    if (this == info->static_type)
+    if (is_equal(this, info->static_type, use_strcmp))
         process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
     else
-        __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below);
+        __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
 }
 
 // This is the same algorithm as __vmi_class_type_info::search_above_dst but
@@ -1029,9 +1103,10 @@
 __class_type_info::search_above_dst(__dynamic_cast_info* info,
                                     const void* dst_ptr,
                                     const void* current_ptr,
-                                    int path_below) const
+                                    int path_below,
+                                    bool use_strcmp) const
 {
-    if (this == info->static_type)
+    if (is_equal(this, info->static_type, use_strcmp))
         process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
 }
 
@@ -1043,7 +1118,8 @@
 __base_class_type_info::search_above_dst(__dynamic_cast_info* info,
                                          const void* dst_ptr,
                                          const void* current_ptr,
-                                         int path_below) const
+                                         int path_below,
+                                         bool use_strcmp) const
 {
     ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
     if (__offset_flags & __virtual_mask)
@@ -1055,13 +1131,15 @@
                                   static_cast<const char*>(current_ptr) + offset_to_base,
                                   (__offset_flags & __public_mask) ?
                                       path_below :
-                                      not_public_path);
+                                      not_public_path,
+                                  use_strcmp);
 }
 
 void
 __base_class_type_info::search_below_dst(__dynamic_cast_info* info,
                                          const void* current_ptr,
-                                         int path_below) const
+                                         int path_below,
+                                         bool use_strcmp) const
 {
     ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
     if (__offset_flags & __virtual_mask)
@@ -1073,7 +1151,8 @@
                                   static_cast<const char*>(current_ptr) + offset_to_base,
                                   (__offset_flags & __public_mask) ?
                                       path_below :
-                                      not_public_path);
+                                      not_public_path,
+                                  use_strcmp);
 }
 
 #pragma GCC visibility pop

Modified: libcxxabi/trunk/src/private_typeinfo.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.h?rev=164863&r1=164862&r2=164863&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.h (original)
+++ libcxxabi/trunk/src/private_typeinfo.h Fri Sep 28 17:43:50 2012
@@ -76,10 +76,10 @@
 {
 // const data supplied to the search:
 
-    const __class_type_info* const dst_type;
-    const void* const static_ptr;
-    const __class_type_info* const static_type;
-    const std::ptrdiff_t src2dst_offset;
+    const __class_type_info* dst_type;
+    const void* static_ptr;
+    const __class_type_info* static_type;
+    std::ptrdiff_t src2dst_offset;
 
 // Data that represents the answer:
 
@@ -133,9 +133,9 @@
     __attribute__ ((__visibility__("hidden")))
         void process_found_base_class(__dynamic_cast_info*, void*, int) const;
     __attribute__ ((__visibility__("hidden")))
-        virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+        virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
     __attribute__ ((__visibility__("hidden")))
-        virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const;
+        virtual void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
     __attribute__ ((__visibility__("hidden")))
         virtual bool can_catch(const __shim_type_info*, void*&) const;
     __attribute__ ((__visibility__("hidden")))
@@ -152,9 +152,9 @@
     __attribute__ ((__visibility__("hidden"))) virtual ~__si_class_type_info();
 
     __attribute__ ((__visibility__("hidden")))
-        virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+        virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
     __attribute__ ((__visibility__("hidden")))
-        virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const;
+        virtual void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
     __attribute__ ((__visibility__("hidden")))
         virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
 };
@@ -172,8 +172,8 @@
         __offset_shift = 8
     };
 
-    void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
-    void search_below_dst(__dynamic_cast_info*, const void*, int) const;
+    void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
+    void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
     void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
 };
 
@@ -197,9 +197,9 @@
     __attribute__ ((__visibility__("hidden"))) virtual ~__vmi_class_type_info();
 
     __attribute__ ((__visibility__("hidden")))
-        virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+        virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
     __attribute__ ((__visibility__("hidden")))
-        virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const;
+        virtual void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
     __attribute__ ((__visibility__("hidden")))
         virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
 };





More information about the cfe-commits mailing list