• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2011 The Android Open Source Project
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 //    notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 //    notice, this list of conditions and the following disclaimer in the
11 //    documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the project nor the names of its contributors
13 //    may be used to endorse or promote products derived from this software
14 //    without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 // SUCH DAMAGE.
27 //
28 // dynamic_cast.cc: RTTI support.
29 //
30 // References:
31 // Itanium C++ ABI at http://www.codesourcery.com/public/cxx-abi/abi.html
32 // IHI0041A C++ Application Binary Interface for the ARM architecture.
33 //
34 
35 #include "cxxabi_defines.h"
36 
37 #include <cstddef>
38 #include <cassert>
39 
40 namespace
41 {
42   // Adjust a pointer by an offset.
43 
44   const void*
adjust_pointer(const void * p,std::ptrdiff_t off)45   adjust_pointer(const void* p, std::ptrdiff_t off)
46   {
47     // FIXME: should we align pointer after adjustment?
48     const char *cp = reinterpret_cast<const char*>(p) + off;
49     return reinterpret_cast<const void*>(cp);
50   }
51 
52   // Return the vtable pointer of a polymorphic object pointed by p.
53 
54   inline const void*
get_vtable(const void * p)55   get_vtable(const void* p)
56   {
57     return *reinterpret_cast<void*const*>(p);
58   }
59 
60   // Return a pointer to a __class_type_info in a vtable.
61 
62   inline const abi::__class_type_info*
get_class_type_info(const void * vtable)63   get_class_type_info(const void* vtable)
64   {
65     const void* type_info_ptr = adjust_pointer(vtable, -sizeof(void*));
66     return *reinterpret_cast<abi::__class_type_info*const*>(type_info_ptr);
67   }
68 
69   // Return offset to object in a vtable.
70 
71   inline std::ptrdiff_t
get_offset_to_top(const void * vtable)72   get_offset_to_top(const void* vtable)
73   {
74     const void* type_info_ptr_address = adjust_pointer(vtable, -sizeof(void*));
75     const void* offset_to_top_address =
76       adjust_pointer(type_info_ptr_address, -sizeof(std::ptrdiff_t));
77     return *reinterpret_cast<const std::ptrdiff_t*>(offset_to_top_address);
78   }
79 
80   // Return the virtual pointer to the most derived object of referred by a
81   // pointer p.
82 
83   const void*
get_most_derived_object(const void * p)84   get_most_derived_object(const void* p)
85   {
86     const void* vtable = get_vtable(p);
87     std::ptrdiff_t offset_to_top = get_offset_to_top(vtable);
88     return adjust_pointer(p, offset_to_top);
89   }
90 
91   // We assume that -1 cannot be a valid pointer to object.
92   const void * const ambiguous_object =
93     reinterpret_cast<const void*>(-1);
94 
95   // Return a pointer to the subobject described by base_info.
96 
97   const void*
get_subobject(const void * object,const void * vtable,const abi::__base_class_type_info * base_info)98   get_subobject(const void* object,
99                 const void* vtable,
100                 const abi::__base_class_type_info* base_info)
101   {
102     long offset = base_info->offset();
103     if (base_info->is_virtual())
104       {
105         const std::ptrdiff_t* virtual_base_offset_address =
106           static_cast<const std::ptrdiff_t*> (adjust_pointer(vtable, offset));
107         offset = *virtual_base_offset_address;
108       }
109     return adjust_pointer(object, offset);
110   }
111 
112   // Helper of __dyanmic_cast to walk the type tree of an object.
113 
114   const void *
walk_object(const void * object,const abi::__class_type_info * type,const void * match_object,const abi::__class_type_info * match_type)115   walk_object(const void *object,
116               const abi::__class_type_info *type,
117               const void *match_object,
118               const abi::__class_type_info *match_type)
119   {
120     if (*type == *match_type)
121       return (match_object == NULL || object == match_object) ? object : NULL;
122 
123     switch(type->code())
124       {
125       case abi::__class_type_info::CLASS_TYPE_INFO_CODE:
126         // This isn't not the class you're looking for.
127         return NULL;
128 
129       case abi::__class_type_info::SI_CLASS_TYPE_INFO_CODE:
130         // derived type has a single public base at offset 0.
131         {
132           const abi::__si_class_type_info* ti =
133             static_cast<const abi::__si_class_type_info*>(type);
134           return walk_object(object, ti->__base_type, match_object,
135                              match_type);
136         }
137 
138       case abi::__class_type_info::VMI_CLASS_TYPE_INFO_CODE:
139         {
140           const void* vtable = get_vtable(object);
141           const abi::__vmi_class_type_info* ti =
142             static_cast<const abi::__vmi_class_type_info*>(type);
143 
144           // Look at all direct bases.
145           const void* result = NULL;
146           for (unsigned i = 0; i < ti->__base_count; ++i)
147             {
148               if (!ti->__base_info[i].is_public())
149                 continue;
150 
151               const void *subobject =
152                 get_subobject(object, vtable, &ti->__base_info[i]);
153               const void* walk_subobject_result =
154                 walk_object(subobject, ti->__base_info[i].__base_type,
155                             match_object, match_type);
156 
157               if (walk_subobject_result == ambiguous_object)
158                 return ambiguous_object;
159               else if (walk_subobject_result != NULL)
160                 {
161                   if (result == NULL)
162                     {
163                       result = walk_subobject_result;
164                     }
165                   else if (result != walk_subobject_result)
166                     return ambiguous_object;
167                 }
168             }
169           return result;
170         }
171 
172       default:
173         assert(0);
174       }
175     return NULL;
176   }
177 
178   // Bookkeeping structure for derived-to-base cast in the general case.
179   struct cast_context
180   {
181   public:
182     const void* object;
183     const abi::__class_type_info *src_type;
184     const abi::__class_type_info *dst_type;
185     std::ptrdiff_t src2dst_offset;
186 
187     const void* dst_object;
188     const void* result;
189 
cast_context__anon521a7ac90111::cast_context190     cast_context(const void* obj, const abi::__class_type_info *src,
191                  const abi::__class_type_info *dst, std::ptrdiff_t offset)
192       : object(obj), src_type(src), dst_type(dst), src2dst_offset(offset),
193         dst_object(NULL), result(NULL)
194     { }
195   };
196 
197   // based-to-derive cast in the general case.
198 
199   void
base_to_derived_cast(const void * object,const abi::__class_type_info * type,cast_context * context)200   base_to_derived_cast(const void *object,
201                        const abi::__class_type_info *type,
202                        cast_context* context)
203   {
204     const void* saved_dst_object = context->dst_object;
205     bool is_dst_type = *type == *context->dst_type;
206     if (is_dst_type)
207       context->dst_object = object;
208 
209     if (object == context->object
210         && context->dst_object != NULL
211         && *type == *context->src_type)
212       {
213         if (context->result == NULL)
214           context->result = context->dst_object;
215         else if (context->result != context->dst_object)
216           context->result = ambiguous_object;
217         context->dst_object = saved_dst_object;
218         return;
219       }
220 
221     switch(type->code())
222       {
223       case abi::__class_type_info::CLASS_TYPE_INFO_CODE:
224         // This isn't not the class you're looking for.
225         break;
226 
227       case abi::__class_type_info::SI_CLASS_TYPE_INFO_CODE:
228         // derived type has a single public base at offset 0.
229         {
230           const abi::__si_class_type_info* ti =
231             static_cast<const abi::__si_class_type_info*>(type);
232           base_to_derived_cast(object, ti->__base_type, context);
233           break;
234         }
235 
236       case abi::__class_type_info::VMI_CLASS_TYPE_INFO_CODE:
237         {
238           const void* vtable = get_vtable(object);
239           const abi::__vmi_class_type_info* ti =
240             static_cast<const abi::__vmi_class_type_info*>(type);
241 
242           // Look at all direct bases.
243           for (unsigned i = 0; i < ti->__base_count; ++i)
244             {
245               if (!ti->__base_info[i].is_public())
246                 continue;
247 
248               const void *subobject =
249                 get_subobject(object, vtable, &ti->__base_info[i]);
250               base_to_derived_cast(subobject, ti->__base_info[i].__base_type,
251                                    context);
252 
253               // FIXME: Use flags in base_info to optimize search.
254               if (context->result == ambiguous_object)
255                 break;
256             }
257           break;
258         }
259 
260       default:
261         assert(0);
262       }
263      context->dst_object = saved_dst_object;
264   }
265 } // namespace
266 
267 namespace __cxxabiv1
268 {
269 #define DYNAMIC_CAST_NO_HINT -1
270 #define DYNAMIC_CAST_NOT_PUBLIC_BASE -2
271 #define DYNAMIC_CAST_MULTIPLE_PUBLIC_NONVIRTUAL_BASE -3
272 
273   /* v: source address to be adjusted; nonnull, and since the
274    *    source object is polymorphic, *(void**)v is a virtual pointer.
275    * src: static type of the source object.
276    * dst: destination type (the "T" in "dynamic_cast<T>(v)").
277    * src2dst_offset: a static hint about the location of the
278    *    source subobject with respect to the complete object;
279    *    special negative values are:
280    *       -1: no hint
281    *       -2: src is not a public base of dst
282    *       -3: src is a multiple public base type but never a
283    *           virtual base type
284    *    otherwise, the src type is a unique public nonvirtual
285    *    base type of dst at offset src2dst_offset from the
286    *    origin of dst.
287    */
288   extern "C" void*
__dynamic_cast(const void * v,const abi::__class_type_info * src,const abi::__class_type_info * dst,std::ptrdiff_t src2dst_offset)289   __dynamic_cast (const void *v,
290                   const abi::__class_type_info *src,
291                   const abi::__class_type_info *dst,
292                   std::ptrdiff_t src2dst_offset)
293   {
294     const void* most_derived_object = get_most_derived_object(v);
295     const void* vtable = get_vtable(most_derived_object);
296     const abi::__class_type_info* most_derived_class_type_info =
297       get_class_type_info(vtable);
298 
299     // If T is not a public base type of the most derived class referred
300     // by v, the cast always fails.
301     void* t_object =
302       const_cast<void*>(walk_object(most_derived_object,
303                                     most_derived_class_type_info, NULL, dst));
304     if (t_object == NULL)
305       return NULL;
306 
307     // C++ ABI 2.9.7 The dynamic_cast Algorithm:
308     //
309     // If, in the most derived object pointed (referred) to by v, v points
310     // (refers) to a public base class subobject of a T object [note: this can
311     // be checked at compile time], and if only one object of type T is derived
312     // from the subobject pointed (referred) to by v, the result is a pointer
313     // (an lvalue referring) to that T object.
314 
315     // We knew that src is not a public base, so base-to-derived cast
316     // is not possible.  This works even if there are multiple subobjects
317     // of type T in the most derived object.
318     if (src2dst_offset != DYNAMIC_CAST_NOT_PUBLIC_BASE)
319       {
320         // If it is known that v points to a public base class subobject
321         // of a T object, simply adjust the pointer by the offset.
322         if (t_object != ambiguous_object && src2dst_offset >= 0)
323           return const_cast<void*>(adjust_pointer(v, -src2dst_offset));
324 
325         // If there is only one T type subobject, we only need to look at
326         // there.  Otherwise, look for the subobject referred by v in the
327         // most derived object.
328         cast_context context(v, src, dst, src2dst_offset);
329         if (t_object != ambiguous_object)
330           base_to_derived_cast(t_object, dst, &context);
331         else
332           base_to_derived_cast(most_derived_object,
333                                most_derived_class_type_info, &context);
334 
335         if (context.result != NULL && context.result != ambiguous_object)
336           return const_cast<void*>(context.result);
337       }
338 
339     // C++ ABI 2.9.7 The dynamic_cast Algorithm:
340     //
341     // Otherwise, if v points (refers) to a public base class subobject of the
342     // most derived object, and the type of the most derived object has an
343     // unambiguous public base class of type T, the result is a pointer (an
344     // lvalue referring) to the T subobject of the most derived object.
345     // Otherwise, the run-time check fails.
346 
347     // Check to see if T is a unambiguous public base class.
348     if (t_object == ambiguous_object)
349       return NULL;
350 
351     // See if v refers to a public base class subobject.
352     const void* v_object =
353       walk_object(most_derived_object, most_derived_class_type_info, v, src);
354     return v_object == v ? t_object : NULL;
355   }
356 } // namespace __cxxabiv1
357