msvcrt: Use pointer exchange to set demangled name instead of section lock.
[wine] / dlls / msvcrt / cpp.c
1 /*
2  * msvcrt.dll C++ objects
3  *
4  * Copyright 2000 Jon Griffiths
5  * Copyright 2003, 2004 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winternl.h"
29 #include "wine/exception.h"
30 #include "wine/debug.h"
31 #include "msvcrt.h"
32 #include "cppexcept.h"
33 #include "mtdll.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36
37 typedef exception bad_cast;
38 typedef exception bad_typeid;
39 typedef exception __non_rtti_object;
40
41 typedef struct _rtti_base_descriptor
42 {
43   const type_info *type_descriptor;
44   int num_base_classes;
45   this_ptr_offsets offsets;    /* offsets for computing the this pointer */
46   unsigned int attributes;
47 } rtti_base_descriptor;
48
49 typedef struct _rtti_base_array
50 {
51   const rtti_base_descriptor *bases[3]; /* First element is the class itself */
52 } rtti_base_array;
53
54 typedef struct _rtti_object_hierarchy
55 {
56   unsigned int signature;
57   unsigned int attributes;
58   int array_len; /* Size of the array pointed to by 'base_classes' */
59   const rtti_base_array *base_classes;
60 } rtti_object_hierarchy;
61
62 typedef struct _rtti_object_locator
63 {
64   unsigned int signature;
65   int base_class_offset;
66   unsigned int flags;
67   const type_info *type_descriptor;
68   const rtti_object_hierarchy *type_hierarchy;
69 } rtti_object_locator;
70
71
72 #ifdef __i386__  /* thiscall functions are i386-specific */
73
74 #define THISCALL(func) __thiscall_ ## func
75 #define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func)
76 #define __thiscall __stdcall
77 #define DEFINE_THISCALL_WRAPPER(func,args) \
78     extern void THISCALL(func)(void); \
79     __ASM_GLOBAL_FUNC(__thiscall_ ## func, \
80                       "popl %eax\n\t" \
81                       "pushl %ecx\n\t" \
82                       "pushl %eax\n\t" \
83                       "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) )
84 #else /* __i386__ */
85
86 #define THISCALL(func) func
87 #define THISCALL_NAME(func) __ASM_NAME(#func)
88 #define __thiscall __cdecl
89 #define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */
90
91 #endif /* __i386__ */
92
93 extern const vtable_ptr MSVCRT_exception_vtable;
94 extern const vtable_ptr MSVCRT_bad_typeid_vtable;
95 extern const vtable_ptr MSVCRT_bad_cast_vtable;
96 extern const vtable_ptr MSVCRT___non_rtti_object_vtable;
97 extern const vtable_ptr MSVCRT_type_info_vtable;
98
99 /* get the vtable pointer for a C++ object */
100 static inline const vtable_ptr *get_vtable( void *obj )
101 {
102     return *(const vtable_ptr **)obj;
103 }
104
105 static inline const rtti_object_locator *get_obj_locator( void *cppobj )
106 {
107     const vtable_ptr *vtable = get_vtable( cppobj );
108     return (const rtti_object_locator *)vtable[-1];
109 }
110
111 static void dump_obj_locator( const rtti_object_locator *ptr )
112 {
113     int i;
114     const rtti_object_hierarchy *h = ptr->type_hierarchy;
115
116     TRACE( "%p: sig=%08x base_offset=%08x flags=%08x type=%p %s hierarchy=%p\n",
117            ptr, ptr->signature, ptr->base_class_offset, ptr->flags,
118            ptr->type_descriptor, dbgstr_type_info(ptr->type_descriptor), ptr->type_hierarchy );
119     TRACE( "  hierarchy: sig=%08x attr=%08x len=%d base classes=%p\n",
120            h->signature, h->attributes, h->array_len, h->base_classes );
121     for (i = 0; i < h->array_len; i++)
122     {
123         TRACE( "    base class %p: num %d off %d,%d,%d attr %08x type %p %s\n",
124                h->base_classes->bases[i],
125                h->base_classes->bases[i]->num_base_classes,
126                h->base_classes->bases[i]->offsets.this_offset,
127                h->base_classes->bases[i]->offsets.vbase_descr,
128                h->base_classes->bases[i]->offsets.vbase_offset,
129                h->base_classes->bases[i]->attributes,
130                h->base_classes->bases[i]->type_descriptor,
131                dbgstr_type_info(h->base_classes->bases[i]->type_descriptor) );
132     }
133 }
134
135 /* Internal common ctor for exception */
136 static void EXCEPTION_ctor(exception *_this, const char** name)
137 {
138   _this->vtable = &MSVCRT_exception_vtable;
139   if (*name)
140   {
141     unsigned int name_len = strlen(*name) + 1;
142     _this->name = MSVCRT_malloc(name_len);
143     memcpy(_this->name, *name, name_len);
144     _this->do_free = TRUE;
145   }
146   else
147   {
148     _this->name = NULL;
149     _this->do_free = FALSE;
150   }
151 }
152
153 /******************************************************************
154  *              ??0exception@@QAE@ABQBD@Z (MSVCRT.@)
155  */
156 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_ctor,8)
157 exception * __thiscall MSVCRT_exception_ctor(exception * _this, const char ** name)
158 {
159   TRACE("(%p,%s)\n", _this, *name);
160   EXCEPTION_ctor(_this, name);
161   return _this;
162 }
163
164 /******************************************************************
165  *              ??0exception@@QAE@ABQBDH@Z (MSVCRT.@)
166  */
167 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_ctor_noalloc,12)
168 exception * __thiscall MSVCRT_exception_ctor_noalloc(exception * _this, char ** name, int noalloc)
169 {
170   TRACE("(%p,%s)\n", _this, *name);
171   _this->vtable = &MSVCRT_exception_vtable;
172   _this->name = *name;
173   _this->do_free = FALSE;
174   return _this;
175 }
176
177 /******************************************************************
178  *              ??0exception@@QAE@ABV0@@Z (MSVCRT.@)
179  */
180 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_copy_ctor,8)
181 exception * __thiscall MSVCRT_exception_copy_ctor(exception * _this, const exception * rhs)
182 {
183   TRACE("(%p,%p)\n", _this, rhs);
184
185   if (!rhs->do_free)
186   {
187     _this->vtable = &MSVCRT_exception_vtable;
188     _this->name = rhs->name;
189     _this->do_free = FALSE;
190   }
191   else
192     EXCEPTION_ctor(_this, (const char**)&rhs->name);
193   TRACE("name = %s\n", _this->name);
194   return _this;
195 }
196
197 /******************************************************************
198  *              ??0exception@@QAE@XZ (MSVCRT.@)
199  */
200 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_default_ctor,4)
201 exception * __thiscall MSVCRT_exception_default_ctor(exception * _this)
202 {
203   static const char* empty = NULL;
204
205   TRACE("(%p)\n", _this);
206   EXCEPTION_ctor(_this, &empty);
207   return _this;
208 }
209
210 /******************************************************************
211  *              ??1exception@@UAE@XZ (MSVCRT.@)
212  */
213 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_dtor,4)
214 void __thiscall MSVCRT_exception_dtor(exception * _this)
215 {
216   TRACE("(%p)\n", _this);
217   _this->vtable = &MSVCRT_exception_vtable;
218   if (_this->do_free) MSVCRT_free(_this->name);
219 }
220
221 /******************************************************************
222  *              ??4exception@@QAEAAV0@ABV0@@Z (MSVCRT.@)
223  */
224 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_opequals,8)
225 exception * __thiscall MSVCRT_exception_opequals(exception * _this, const exception * rhs)
226 {
227   TRACE("(%p %p)\n", _this, rhs);
228   if (_this != rhs)
229   {
230       MSVCRT_exception_dtor(_this);
231       MSVCRT_exception_copy_ctor(_this, rhs);
232   }
233   TRACE("name = %s\n", _this->name);
234   return _this;
235 }
236
237 /******************************************************************
238  *              ??_Eexception@@UAEPAXI@Z (MSVCRT.@)
239  */
240 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_vector_dtor,8)
241 void * __thiscall MSVCRT_exception_vector_dtor(exception * _this, unsigned int flags)
242 {
243     TRACE("(%p %x)\n", _this, flags);
244     if (flags & 2)
245     {
246         /* we have an array, with the number of elements stored before the first object */
247         int i, *ptr = (int *)_this - 1;
248
249         for (i = *ptr - 1; i >= 0; i--) MSVCRT_exception_dtor(_this + i);
250         MSVCRT_operator_delete(ptr);
251     }
252     else
253     {
254         MSVCRT_exception_dtor(_this);
255         if (flags & 1) MSVCRT_operator_delete(_this);
256     }
257     return _this;
258 }
259
260 /******************************************************************
261  *              ??_Gexception@@UAEPAXI@Z (MSVCRT.@)
262  */
263 DEFINE_THISCALL_WRAPPER(MSVCRT_exception_scalar_dtor,8)
264 void * __thiscall MSVCRT_exception_scalar_dtor(exception * _this, unsigned int flags)
265 {
266     TRACE("(%p %x)\n", _this, flags);
267     MSVCRT_exception_dtor(_this);
268     if (flags & 1) MSVCRT_operator_delete(_this);
269     return _this;
270 }
271
272 /******************************************************************
273  *              ?what@exception@@UBEPBDXZ (MSVCRT.@)
274  */
275 DEFINE_THISCALL_WRAPPER(MSVCRT_what_exception,4)
276 const char * __thiscall MSVCRT_what_exception(exception * _this)
277 {
278   TRACE("(%p) returning %s\n", _this, _this->name);
279   return _this->name ? _this->name : "Unknown exception";
280 }
281
282 /******************************************************************
283  *              ??0bad_typeid@@QAE@ABV0@@Z (MSVCRT.@)
284  */
285 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_copy_ctor,8)
286 bad_typeid * __thiscall MSVCRT_bad_typeid_copy_ctor(bad_typeid * _this, const bad_typeid * rhs)
287 {
288   TRACE("(%p %p)\n", _this, rhs);
289   MSVCRT_exception_copy_ctor(_this, rhs);
290   _this->vtable = &MSVCRT_bad_typeid_vtable;
291   return _this;
292 }
293
294 /******************************************************************
295  *              ??0bad_typeid@@QAE@PBD@Z (MSVCRT.@)
296  */
297 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_ctor,8)
298 bad_typeid * __thiscall MSVCRT_bad_typeid_ctor(bad_typeid * _this, const char * name)
299 {
300   TRACE("(%p %s)\n", _this, name);
301   EXCEPTION_ctor(_this, &name);
302   _this->vtable = &MSVCRT_bad_typeid_vtable;
303   return _this;
304 }
305
306 /******************************************************************
307  *              ??_Fbad_typeid@@QAEXXZ (MSVCRT.@)
308  */
309 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_default_ctor,4)
310 bad_typeid * __thiscall MSVCRT_bad_typeid_default_ctor(bad_typeid * _this)
311 {
312   return MSVCRT_bad_typeid_ctor( _this, "bad typeid" );
313 }
314
315 /******************************************************************
316  *              ??1bad_typeid@@UAE@XZ (MSVCRT.@)
317  */
318 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_dtor,4)
319 void __thiscall MSVCRT_bad_typeid_dtor(bad_typeid * _this)
320 {
321   TRACE("(%p)\n", _this);
322   MSVCRT_exception_dtor(_this);
323 }
324
325 /******************************************************************
326  *              ??4bad_typeid@@QAEAAV0@ABV0@@Z (MSVCRT.@)
327  */
328 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_opequals,8)
329 bad_typeid * __thiscall MSVCRT_bad_typeid_opequals(bad_typeid * _this, const bad_typeid * rhs)
330 {
331   TRACE("(%p %p)\n", _this, rhs);
332   MSVCRT_exception_opequals(_this, rhs);
333   return _this;
334 }
335
336 /******************************************************************
337  *              ??_Ebad_typeid@@UAEPAXI@Z (MSVCRT.@)
338  */
339 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_vector_dtor,8)
340 void * __thiscall MSVCRT_bad_typeid_vector_dtor(bad_typeid * _this, unsigned int flags)
341 {
342     TRACE("(%p %x)\n", _this, flags);
343     if (flags & 2)
344     {
345         /* we have an array, with the number of elements stored before the first object */
346         int i, *ptr = (int *)_this - 1;
347
348         for (i = *ptr - 1; i >= 0; i--) MSVCRT_bad_typeid_dtor(_this + i);
349         MSVCRT_operator_delete(ptr);
350     }
351     else
352     {
353         MSVCRT_bad_typeid_dtor(_this);
354         if (flags & 1) MSVCRT_operator_delete(_this);
355     }
356     return _this;
357 }
358
359 /******************************************************************
360  *              ??_Gbad_typeid@@UAEPAXI@Z (MSVCRT.@)
361  */
362 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_scalar_dtor,8)
363 void * __thiscall MSVCRT_bad_typeid_scalar_dtor(bad_typeid * _this, unsigned int flags)
364 {
365     TRACE("(%p %x)\n", _this, flags);
366     MSVCRT_bad_typeid_dtor(_this);
367     if (flags & 1) MSVCRT_operator_delete(_this);
368     return _this;
369 }
370
371 /******************************************************************
372  *              ??0__non_rtti_object@@QAE@ABV0@@Z (MSVCRT.@)
373  */
374 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_copy_ctor,8)
375 __non_rtti_object * __thiscall MSVCRT___non_rtti_object_copy_ctor(__non_rtti_object * _this,
376                                                                  const __non_rtti_object * rhs)
377 {
378   TRACE("(%p %p)\n", _this, rhs);
379   MSVCRT_bad_typeid_copy_ctor(_this, rhs);
380   _this->vtable = &MSVCRT___non_rtti_object_vtable;
381   return _this;
382 }
383
384 /******************************************************************
385  *              ??0__non_rtti_object@@QAE@PBD@Z (MSVCRT.@)
386  */
387 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_ctor,8)
388 __non_rtti_object * __thiscall MSVCRT___non_rtti_object_ctor(__non_rtti_object * _this,
389                                                             const char * name)
390 {
391   TRACE("(%p %s)\n", _this, name);
392   EXCEPTION_ctor(_this, &name);
393   _this->vtable = &MSVCRT___non_rtti_object_vtable;
394   return _this;
395 }
396
397 /******************************************************************
398  *              ??1__non_rtti_object@@UAE@XZ (MSVCRT.@)
399  */
400 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_dtor,4)
401 void __thiscall MSVCRT___non_rtti_object_dtor(__non_rtti_object * _this)
402 {
403   TRACE("(%p)\n", _this);
404   MSVCRT_bad_typeid_dtor(_this);
405 }
406
407 /******************************************************************
408  *              ??4__non_rtti_object@@QAEAAV0@ABV0@@Z (MSVCRT.@)
409  */
410 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_opequals,8)
411 __non_rtti_object * __thiscall MSVCRT___non_rtti_object_opequals(__non_rtti_object * _this,
412                                                                 const __non_rtti_object *rhs)
413 {
414   TRACE("(%p %p)\n", _this, rhs);
415   MSVCRT_bad_typeid_opequals(_this, rhs);
416   return _this;
417 }
418
419 /******************************************************************
420  *              ??_E__non_rtti_object@@UAEPAXI@Z (MSVCRT.@)
421  */
422 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_vector_dtor,8)
423 void * __thiscall MSVCRT___non_rtti_object_vector_dtor(__non_rtti_object * _this, unsigned int flags)
424 {
425     TRACE("(%p %x)\n", _this, flags);
426     if (flags & 2)
427     {
428         /* we have an array, with the number of elements stored before the first object */
429         int i, *ptr = (int *)_this - 1;
430
431         for (i = *ptr - 1; i >= 0; i--) MSVCRT___non_rtti_object_dtor(_this + i);
432         MSVCRT_operator_delete(ptr);
433     }
434     else
435     {
436         MSVCRT___non_rtti_object_dtor(_this);
437         if (flags & 1) MSVCRT_operator_delete(_this);
438     }
439     return _this;
440 }
441
442 /******************************************************************
443  *              ??_G__non_rtti_object@@UAEPAXI@Z (MSVCRT.@)
444  */
445 DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_scalar_dtor,8)
446 void * __thiscall MSVCRT___non_rtti_object_scalar_dtor(__non_rtti_object * _this, unsigned int flags)
447 {
448   TRACE("(%p %x)\n", _this, flags);
449   MSVCRT___non_rtti_object_dtor(_this);
450   if (flags & 1) MSVCRT_operator_delete(_this);
451   return _this;
452 }
453
454 /******************************************************************
455  *              ??0bad_cast@@AAE@PBQBD@Z (MSVCRT.@)
456  *              ??0bad_cast@@QAE@ABQBD@Z (MSVCRT.@)
457  */
458 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_ctor,8)
459 bad_cast * __thiscall MSVCRT_bad_cast_ctor(bad_cast * _this, const char ** name)
460 {
461   TRACE("(%p %s)\n", _this, *name);
462   EXCEPTION_ctor(_this, name);
463   _this->vtable = &MSVCRT_bad_cast_vtable;
464   return _this;
465 }
466
467 /******************************************************************
468  *              ??0bad_cast@@QAE@ABV0@@Z (MSVCRT.@)
469  */
470 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_copy_ctor,8)
471 bad_cast * __thiscall MSVCRT_bad_cast_copy_ctor(bad_cast * _this, const bad_cast * rhs)
472 {
473   TRACE("(%p %p)\n", _this, rhs);
474   MSVCRT_exception_copy_ctor(_this, rhs);
475   _this->vtable = &MSVCRT_bad_cast_vtable;
476   return _this;
477 }
478
479 /******************************************************************
480  *              ??0bad_cast@@QAE@PBD@Z (MSVCRT.@)
481  */
482 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_ctor_charptr,8)
483 bad_cast * __thiscall MSVCRT_bad_cast_ctor_charptr(bad_cast * _this, const char * name)
484 {
485   TRACE("(%p %s)\n", _this, name);
486   EXCEPTION_ctor(_this, &name);
487   _this->vtable = &MSVCRT_bad_cast_vtable;
488   return _this;
489 }
490
491 /******************************************************************
492  *              ??_Fbad_cast@@QAEXXZ (MSVCRT.@)
493  */
494 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_default_ctor,4)
495 bad_cast * __thiscall MSVCRT_bad_cast_default_ctor(bad_cast * _this)
496 {
497   return MSVCRT_bad_cast_ctor_charptr( _this, "bad cast" );
498 }
499
500 /******************************************************************
501  *              ??1bad_cast@@UAE@XZ (MSVCRT.@)
502  */
503 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_dtor,4)
504 void __thiscall MSVCRT_bad_cast_dtor(bad_cast * _this)
505 {
506   TRACE("(%p)\n", _this);
507   MSVCRT_exception_dtor(_this);
508 }
509
510 /******************************************************************
511  *              ??4bad_cast@@QAEAAV0@ABV0@@Z (MSVCRT.@)
512  */
513 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_opequals,8)
514 bad_cast * __thiscall MSVCRT_bad_cast_opequals(bad_cast * _this, const bad_cast * rhs)
515 {
516   TRACE("(%p %p)\n", _this, rhs);
517   MSVCRT_exception_opequals(_this, rhs);
518   return _this;
519 }
520
521 /******************************************************************
522  *              ??_Ebad_cast@@UAEPAXI@Z (MSVCRT.@)
523  */
524 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_vector_dtor,8)
525 void * __thiscall MSVCRT_bad_cast_vector_dtor(bad_cast * _this, unsigned int flags)
526 {
527     TRACE("(%p %x)\n", _this, flags);
528     if (flags & 2)
529     {
530         /* we have an array, with the number of elements stored before the first object */
531         int i, *ptr = (int *)_this - 1;
532
533         for (i = *ptr - 1; i >= 0; i--) MSVCRT_bad_cast_dtor(_this + i);
534         MSVCRT_operator_delete(ptr);
535     }
536     else
537     {
538         MSVCRT_bad_cast_dtor(_this);
539         if (flags & 1) MSVCRT_operator_delete(_this);
540     }
541     return _this;
542 }
543
544 /******************************************************************
545  *              ??_Gbad_cast@@UAEPAXI@Z (MSVCRT.@)
546  */
547 DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_scalar_dtor,8)
548 void * __thiscall MSVCRT_bad_cast_scalar_dtor(bad_cast * _this, unsigned int flags)
549 {
550   TRACE("(%p %x)\n", _this, flags);
551   MSVCRT_bad_cast_dtor(_this);
552   if (flags & 1) MSVCRT_operator_delete(_this);
553   return _this;
554 }
555
556 /******************************************************************
557  *              ??8type_info@@QBEHABV0@@Z (MSVCRT.@)
558  */
559 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opequals_equals,8)
560 int __thiscall MSVCRT_type_info_opequals_equals(type_info * _this, const type_info * rhs)
561 {
562     int ret = !strcmp(_this->mangled + 1, rhs->mangled + 1);
563     TRACE("(%p %p) returning %d\n", _this, rhs, ret);
564     return ret;
565 }
566
567 /******************************************************************
568  *              ??9type_info@@QBEHABV0@@Z (MSVCRT.@)
569  */
570 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opnot_equals,8)
571 int __thiscall MSVCRT_type_info_opnot_equals(type_info * _this, const type_info * rhs)
572 {
573     int ret = !!strcmp(_this->mangled + 1, rhs->mangled + 1);
574     TRACE("(%p %p) returning %d\n", _this, rhs, ret);
575     return ret;
576 }
577
578 /******************************************************************
579  *              ?before@type_info@@QBEHABV1@@Z (MSVCRT.@)
580  */
581 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_before,8)
582 int __thiscall MSVCRT_type_info_before(type_info * _this, const type_info * rhs)
583 {
584     int ret = strcmp(_this->mangled + 1, rhs->mangled + 1) < 0;
585     TRACE("(%p %p) returning %d\n", _this, rhs, ret);
586     return ret;
587 }
588
589 /******************************************************************
590  *              ??1type_info@@UAE@XZ (MSVCRT.@)
591  */
592 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_dtor,4)
593 void __thiscall MSVCRT_type_info_dtor(type_info * _this)
594 {
595   TRACE("(%p)\n", _this);
596   MSVCRT_free(_this->name);
597 }
598
599 /******************************************************************
600  *              ?name@type_info@@QBEPBDXZ (MSVCRT.@)
601  */
602 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_name,4)
603 const char * __thiscall MSVCRT_type_info_name(type_info * _this)
604 {
605   if (!_this->name)
606   {
607     /* Create and set the demangled name */
608     /* Nota: mangled name in type_info struct always start with a '.', while
609      * it isn't valid for mangled name.
610      * Is this '.' really part of the mangled name, or has it some other meaning ?
611      */
612     char* name = __unDName(0, _this->mangled + 1, 0,
613                            MSVCRT_malloc, MSVCRT_free, 0x2800);
614     if (name)
615     {
616       unsigned int len = strlen(name);
617
618       /* It seems _unDName may leave blanks at the end of the demangled name */
619       while (len && name[--len] == ' ')
620         name[len] = '\0';
621
622       if (InterlockedCompareExchangePointer((void**)&_this->name, name, NULL))
623       {
624         /* Another thread set this member since we checked above - use it */
625         MSVCRT_free(name);
626       }
627     }
628   }
629   TRACE("(%p) returning %s\n", _this, _this->name);
630   return _this->name;
631 }
632
633 /******************************************************************
634  *              ?raw_name@type_info@@QBEPBDXZ (MSVCRT.@)
635  */
636 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_raw_name,4)
637 const char * __thiscall MSVCRT_type_info_raw_name(type_info * _this)
638 {
639   TRACE("(%p) returning %s\n", _this, _this->mangled);
640   return _this->mangled;
641 }
642
643 /* Unexported */
644 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_vector_dtor,8)
645 void * __thiscall MSVCRT_type_info_vector_dtor(type_info * _this, unsigned int flags)
646 {
647     TRACE("(%p %x)\n", _this, flags);
648     if (flags & 2)
649     {
650         /* we have an array, with the number of elements stored before the first object */
651         int i, *ptr = (int *)_this - 1;
652
653         for (i = *ptr - 1; i >= 0; i--) MSVCRT_type_info_dtor(_this + i);
654         MSVCRT_operator_delete(ptr);
655     }
656     else
657     {
658         MSVCRT_type_info_dtor(_this);
659         if (flags & 1) MSVCRT_operator_delete(_this);
660     }
661     return _this;
662 }
663
664 /* vtables */
665
666 #ifdef _WIN64
667
668 #define __ASM_VTABLE(name,funcs) \
669     __asm__(".data\n" \
670             "\t.align 8\n" \
671             "\t.quad " __ASM_NAME(#name "_rtti") "\n" \
672             "\t.globl " __ASM_NAME("MSVCRT_" #name "_vtable") "\n" \
673             __ASM_NAME("MSVCRT_" #name "_vtable") ":\n" \
674             "\t.quad " THISCALL_NAME(MSVCRT_ ## name ## _vector_dtor) "\n" \
675             funcs "\n\t.text");
676
677 #define __ASM_EXCEPTION_VTABLE(name) \
678     __ASM_VTABLE(name, "\t.quad " THISCALL_NAME(MSVCRT_what_exception) )
679
680 #else
681
682 #define __ASM_VTABLE(name,funcs) \
683     __asm__(".data\n" \
684             "\t.align 4\n" \
685             "\t.long " __ASM_NAME(#name "_rtti") "\n" \
686             "\t.globl " __ASM_NAME("MSVCRT_" #name "_vtable") "\n" \
687             __ASM_NAME("MSVCRT_" #name "_vtable") ":\n" \
688             "\t.long " THISCALL_NAME(MSVCRT_ ## name ## _vector_dtor) "\n" \
689             funcs "\n\t.text");
690
691 #define __ASM_EXCEPTION_VTABLE(name) \
692     __ASM_VTABLE(name, "\t.long " THISCALL_NAME(MSVCRT_what_exception) )
693
694 #endif /* _WIN64 */
695
696 #ifndef __GNUC__
697 void __asm_dummy_vtables(void) {
698 #endif
699
700 __ASM_VTABLE(type_info,"")
701 __ASM_EXCEPTION_VTABLE(exception)
702 __ASM_EXCEPTION_VTABLE(bad_typeid)
703 __ASM_EXCEPTION_VTABLE(bad_cast)
704 __ASM_EXCEPTION_VTABLE(__non_rtti_object)
705
706 #ifndef __GNUC__
707 }
708 #endif
709
710 /* Static RTTI for exported objects */
711
712 static const type_info exception_type_info =
713 {
714   &MSVCRT_type_info_vtable,
715   NULL,
716   ".?AVexception@@"
717 };
718
719 static const rtti_base_descriptor exception_rtti_base_descriptor =
720 {
721   &exception_type_info,
722   0,
723   { 0, -1, 0 },
724   0
725 };
726
727 static const rtti_base_array exception_rtti_base_array =
728 {
729   {
730     &exception_rtti_base_descriptor,
731     NULL,
732     NULL
733   }
734 };
735
736 static const rtti_object_hierarchy exception_type_hierarchy =
737 {
738   0,
739   0,
740   1,
741   &exception_rtti_base_array
742 };
743
744 const rtti_object_locator exception_rtti =
745 {
746   0,
747   0,
748   0,
749   &exception_type_info,
750   &exception_type_hierarchy
751 };
752
753 static const cxx_type_info exception_cxx_type_info =
754 {
755   0,
756   &exception_type_info,
757   { 0, -1, 0 },
758   sizeof(exception),
759   (cxx_copy_ctor)THISCALL(MSVCRT_exception_copy_ctor)
760 };
761
762 static const type_info bad_typeid_type_info =
763 {
764   &MSVCRT_type_info_vtable,
765   NULL,
766   ".?AVbad_typeid@@"
767 };
768
769 static const rtti_base_descriptor bad_typeid_rtti_base_descriptor =
770 {
771   &bad_typeid_type_info,
772   1,
773   { 0, -1, 0 },
774   0
775 };
776
777 static const rtti_base_array bad_typeid_rtti_base_array =
778 {
779   {
780     &bad_typeid_rtti_base_descriptor,
781     &exception_rtti_base_descriptor,
782     NULL
783   }
784 };
785
786 static const rtti_object_hierarchy bad_typeid_type_hierarchy =
787 {
788   0,
789   0,
790   2,
791   &bad_typeid_rtti_base_array
792 };
793
794 const rtti_object_locator bad_typeid_rtti =
795 {
796   0,
797   0,
798   0,
799   &bad_typeid_type_info,
800   &bad_typeid_type_hierarchy
801 };
802
803 static const cxx_type_info bad_typeid_cxx_type_info =
804 {
805   0,
806   &bad_typeid_type_info,
807   { 0, -1, 0 },
808   sizeof(exception),
809   (cxx_copy_ctor)THISCALL(MSVCRT_bad_typeid_copy_ctor)
810 };
811
812 static const type_info bad_cast_type_info =
813 {
814   &MSVCRT_type_info_vtable,
815   NULL,
816   ".?AVbad_cast@@"
817 };
818
819 static const rtti_base_descriptor bad_cast_rtti_base_descriptor =
820 {
821   &bad_cast_type_info,
822   1,
823   { 0, -1, 0 },
824   0
825 };
826
827 static const rtti_base_array bad_cast_rtti_base_array =
828 {
829   {
830     &bad_cast_rtti_base_descriptor,
831     &exception_rtti_base_descriptor,
832     NULL
833   }
834 };
835
836 static const rtti_object_hierarchy bad_cast_type_hierarchy =
837 {
838   0,
839   0,
840   2,
841   &bad_cast_rtti_base_array
842 };
843
844 const rtti_object_locator bad_cast_rtti =
845 {
846   0,
847   0,
848   0,
849   &bad_cast_type_info,
850   &bad_cast_type_hierarchy
851 };
852
853 static const cxx_type_info bad_cast_cxx_type_info =
854 {
855   0,
856   &bad_cast_type_info,
857   { 0, -1, 0 },
858   sizeof(exception),
859   (cxx_copy_ctor)THISCALL(MSVCRT_bad_cast_copy_ctor)
860 };
861
862 static const type_info __non_rtti_object_type_info =
863 {
864   &MSVCRT_type_info_vtable,
865   NULL,
866   ".?AV__non_rtti_object@@"
867 };
868
869 static const rtti_base_descriptor __non_rtti_object_rtti_base_descriptor =
870 {
871   &__non_rtti_object_type_info,
872   2,
873   { 0, -1, 0 },
874   0
875 };
876
877 static const rtti_base_array __non_rtti_object_rtti_base_array =
878 {
879   {
880     &__non_rtti_object_rtti_base_descriptor,
881     &bad_typeid_rtti_base_descriptor,
882     &exception_rtti_base_descriptor
883   }
884 };
885
886 static const rtti_object_hierarchy __non_rtti_object_type_hierarchy =
887 {
888   0,
889   0,
890   3,
891   &__non_rtti_object_rtti_base_array
892 };
893
894 const rtti_object_locator __non_rtti_object_rtti =
895 {
896   0,
897   0,
898   0,
899   &__non_rtti_object_type_info,
900   &__non_rtti_object_type_hierarchy
901 };
902
903 static const cxx_type_info __non_rtti_object_cxx_type_info =
904 {
905   0,
906   &__non_rtti_object_type_info,
907   { 0, -1, 0 },
908   sizeof(exception),
909   (cxx_copy_ctor)THISCALL(MSVCRT___non_rtti_object_copy_ctor)
910 };
911
912 static const type_info type_info_type_info =
913 {
914   &MSVCRT_type_info_vtable,
915   NULL,
916   ".?AVtype_info@@"
917 };
918
919 static const rtti_base_descriptor type_info_rtti_base_descriptor =
920 {
921   &type_info_type_info,
922   0,
923   { 0, -1, 0 },
924   0
925 };
926
927 static const rtti_base_array type_info_rtti_base_array =
928 {
929   {
930     &type_info_rtti_base_descriptor,
931     NULL,
932     NULL
933   }
934 };
935
936 static const rtti_object_hierarchy type_info_type_hierarchy =
937 {
938   0,
939   0,
940   1,
941   &type_info_rtti_base_array
942 };
943
944 const rtti_object_locator type_info_rtti =
945 {
946   0,
947   0,
948   0,
949   &type_info_type_info,
950   &type_info_type_hierarchy
951 };
952
953 /*
954  * Exception RTTI for cpp objects
955  */
956 static const cxx_type_info_table bad_cast_type_info_table =
957 {
958   3,
959   {
960    &__non_rtti_object_cxx_type_info,
961    &bad_typeid_cxx_type_info,
962    &exception_cxx_type_info
963   }
964 };
965
966 static const cxx_exception_type bad_cast_exception_type =
967 {
968   0,
969   (void*)THISCALL(MSVCRT_bad_cast_dtor),
970   NULL,
971   &bad_cast_type_info_table
972 };
973
974 static const cxx_type_info_table bad_typeid_type_info_table =
975 {
976   2,
977   {
978    &bad_cast_cxx_type_info,
979    &exception_cxx_type_info,
980    NULL
981   }
982 };
983
984 static const cxx_exception_type bad_typeid_exception_type =
985 {
986   0,
987   (void*)THISCALL(MSVCRT_bad_typeid_dtor),
988   NULL,
989   &bad_cast_type_info_table
990 };
991
992 static const cxx_exception_type __non_rtti_object_exception_type =
993 {
994   0,
995   (void*)THISCALL(MSVCRT___non_rtti_object_dtor),
996   NULL,
997   &bad_typeid_type_info_table
998 };
999
1000
1001 /******************************************************************
1002  *              ?set_terminate@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
1003  *
1004  * Install a handler to be called when terminate() is called.
1005  *
1006  * PARAMS
1007  *  func [I] Handler function to install
1008  *
1009  * RETURNS
1010  *  The previously installed handler function, if any.
1011  */
1012 MSVCRT_terminate_function CDECL MSVCRT_set_terminate(MSVCRT_terminate_function func)
1013 {
1014     thread_data_t *data = msvcrt_get_thread_data();
1015     MSVCRT_terminate_function previous = data->terminate_handler;
1016     TRACE("(%p) returning %p\n",func,previous);
1017     data->terminate_handler = func;
1018     return previous;
1019 }
1020
1021 /******************************************************************
1022  *              _get_terminate (MSVCRT.@)
1023  */
1024 MSVCRT_terminate_function CDECL MSVCRT__get_terminate(void)
1025 {
1026     thread_data_t *data = msvcrt_get_thread_data();
1027     TRACE("returning %p\n", data->terminate_handler);
1028     return data->terminate_handler;
1029 }
1030
1031 /******************************************************************
1032  *              ?set_unexpected@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
1033  *
1034  * Install a handler to be called when unexpected() is called.
1035  *
1036  * PARAMS
1037  *  func [I] Handler function to install
1038  *
1039  * RETURNS
1040  *  The previously installed handler function, if any.
1041  */
1042 MSVCRT_unexpected_function CDECL MSVCRT_set_unexpected(MSVCRT_unexpected_function func)
1043 {
1044     thread_data_t *data = msvcrt_get_thread_data();
1045     MSVCRT_unexpected_function previous = data->unexpected_handler;
1046     TRACE("(%p) returning %p\n",func,previous);
1047     data->unexpected_handler = func;
1048     return previous;
1049 }
1050
1051 /******************************************************************
1052  *              ?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z  (MSVCRT.@)
1053  */
1054 MSVCRT__se_translator_function CDECL MSVCRT__set_se_translator(MSVCRT__se_translator_function func)
1055 {
1056     thread_data_t *data = msvcrt_get_thread_data();
1057     MSVCRT__se_translator_function previous = data->se_translator;
1058     TRACE("(%p) returning %p\n",func,previous);
1059     data->se_translator = func;
1060     return previous;
1061 }
1062
1063 /******************************************************************
1064  *              ?terminate@@YAXXZ (MSVCRT.@)
1065  *
1066  * Default handler for an unhandled exception.
1067  *
1068  * PARAMS
1069  *  None.
1070  *
1071  * RETURNS
1072  *  This function does not return. Either control resumes from any
1073  *  handler installed by calling set_terminate(), or (by default) abort()
1074  *  is called.
1075  */
1076 void CDECL MSVCRT_terminate(void)
1077 {
1078     thread_data_t *data = msvcrt_get_thread_data();
1079     if (data->terminate_handler) data->terminate_handler();
1080     MSVCRT_abort();
1081 }
1082
1083 /******************************************************************
1084  *              ?unexpected@@YAXXZ (MSVCRT.@)
1085  */
1086 void CDECL MSVCRT_unexpected(void)
1087 {
1088     thread_data_t *data = msvcrt_get_thread_data();
1089     if (data->unexpected_handler) data->unexpected_handler();
1090     MSVCRT_terminate();
1091 }
1092
1093
1094 /******************************************************************
1095  *              __RTtypeid (MSVCRT.@)
1096  *
1097  * Retrieve the Run Time Type Information (RTTI) for a C++ object.
1098  *
1099  * PARAMS
1100  *  cppobj [I] C++ object to get type information for.
1101  *
1102  * RETURNS
1103  *  Success: A type_info object describing cppobj.
1104  *  Failure: If the object to be cast has no RTTI, a __non_rtti_object
1105  *           exception is thrown. If cppobj is NULL, a bad_typeid exception
1106  *           is thrown. In either case, this function does not return.
1107  *
1108  * NOTES
1109  *  This function is usually called by compiler generated code as a result
1110  *  of using one of the C++ dynamic cast statements.
1111  */
1112 const type_info* CDECL MSVCRT___RTtypeid(void *cppobj)
1113 {
1114     const type_info *ret;
1115
1116     if (!cppobj)
1117     {
1118         bad_typeid e;
1119         MSVCRT_bad_typeid_ctor( &e, "Attempted a typeid of NULL pointer!" );
1120         _CxxThrowException( &e, &bad_typeid_exception_type );
1121         return NULL;
1122     }
1123
1124     __TRY
1125     {
1126         const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
1127         ret = obj_locator->type_descriptor;
1128     }
1129     __EXCEPT_PAGE_FAULT
1130     {
1131         __non_rtti_object e;
1132         MSVCRT___non_rtti_object_ctor( &e, "Bad read pointer - no RTTI data!" );
1133         _CxxThrowException( &e, &bad_typeid_exception_type );
1134         return NULL;
1135     }
1136     __ENDTRY
1137     return ret;
1138 }
1139
1140 /******************************************************************
1141  *              __RTDynamicCast (MSVCRT.@)
1142  *
1143  * Dynamically cast a C++ object to one of its base classes.
1144  *
1145  * PARAMS
1146  *  cppobj   [I] Any C++ object to cast
1147  *  unknown  [I] Reserved, set to 0
1148  *  src      [I] type_info object describing cppobj
1149  *  dst      [I] type_info object describing the base class to cast to
1150  *  do_throw [I] TRUE = throw an exception if the cast fails, FALSE = don't
1151  *
1152  * RETURNS
1153  *  Success: The address of cppobj, cast to the object described by dst.
1154  *  Failure: NULL, If the object to be cast has no RTTI, or dst is not a
1155  *           valid cast for cppobj. If do_throw is TRUE, a bad_cast exception
1156  *           is thrown and this function does not return.
1157  *
1158  * NOTES
1159  *  This function is usually called by compiler generated code as a result
1160  *  of using one of the C++ dynamic cast statements.
1161  */
1162 void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown,
1163                                    type_info *src, type_info *dst,
1164                                    int do_throw)
1165 {
1166     void *ret;
1167
1168     if (!cppobj) return NULL;
1169
1170     TRACE("obj: %p unknown: %d src: %p %s dst: %p %s do_throw: %d)\n",
1171           cppobj, unknown, src, dbgstr_type_info(src), dst, dbgstr_type_info(dst), do_throw);
1172
1173     /* To cast an object at runtime:
1174      * 1.Find out the true type of the object from the typeinfo at vtable[-1]
1175      * 2.Search for the destination type in the class hierarchy
1176      * 3.If destination type is found, return base object address + dest offset
1177      *   Otherwise, fail the cast
1178      *
1179      * FIXME: the unknown parameter doesn't seem to be used for anything
1180      */
1181     __TRY
1182     {
1183         int i;
1184         const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
1185         const rtti_object_hierarchy *obj_bases = obj_locator->type_hierarchy;
1186         const rtti_base_descriptor * const* base_desc = obj_bases->base_classes->bases;
1187
1188         if (TRACE_ON(msvcrt)) dump_obj_locator(obj_locator);
1189
1190         ret = NULL;
1191         for (i = 0; i < obj_bases->array_len; i++)
1192         {
1193             const type_info *typ = base_desc[i]->type_descriptor;
1194
1195             if (!strcmp(typ->mangled, dst->mangled))
1196             {
1197                 /* compute the correct this pointer for that base class */
1198                 void *this_ptr = (char *)cppobj - obj_locator->base_class_offset;
1199                 ret = get_this_pointer( &base_desc[i]->offsets, this_ptr );
1200                 break;
1201             }
1202         }
1203         /* VC++ sets do_throw to 1 when the result of a dynamic_cast is assigned
1204          * to a reference, since references cannot be NULL.
1205          */
1206         if (!ret && do_throw)
1207         {
1208             const char *msg = "Bad dynamic_cast!";
1209             bad_cast e;
1210             MSVCRT_bad_cast_ctor( &e, &msg );
1211             _CxxThrowException( &e, &bad_cast_exception_type );
1212         }
1213     }
1214     __EXCEPT_PAGE_FAULT
1215     {
1216         __non_rtti_object e;
1217         MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" );
1218         _CxxThrowException( &e, &bad_typeid_exception_type );
1219         return NULL;
1220     }
1221     __ENDTRY
1222     return ret;
1223 }
1224
1225
1226 /******************************************************************
1227  *              __RTCastToVoid (MSVCRT.@)
1228  *
1229  * Dynamically cast a C++ object to a void*.
1230  *
1231  * PARAMS
1232  *  cppobj [I] The C++ object to cast
1233  *
1234  * RETURNS
1235  *  Success: The base address of the object as a void*.
1236  *  Failure: NULL, if cppobj is NULL or has no RTTI.
1237  *
1238  * NOTES
1239  *  This function is usually called by compiler generated code as a result
1240  *  of using one of the C++ dynamic cast statements.
1241  */
1242 void* CDECL MSVCRT___RTCastToVoid(void *cppobj)
1243 {
1244     void *ret;
1245
1246     if (!cppobj) return NULL;
1247
1248     __TRY
1249     {
1250         const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
1251         ret = (char *)cppobj - obj_locator->base_class_offset;
1252     }
1253     __EXCEPT_PAGE_FAULT
1254     {
1255         __non_rtti_object e;
1256         MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" );
1257         _CxxThrowException( &e, &bad_typeid_exception_type );
1258         return NULL;
1259     }
1260     __ENDTRY
1261     return ret;
1262 }