cpp.c 46.4 KB
Newer Older
1 2 3 4
/*
 * msvcrt.dll C++ objects
 *
 * Copyright 2000 Jon Griffiths
5
 * Copyright 2003, 2004 Alexandre Julliard
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 23 24
#include "config.h"
#include "wine/port.h"

25 26 27
#include <stdarg.h>

#include "windef.h"
28 29 30 31 32 33
#include "winternl.h"
#include "wine/exception.h"
#include "wine/debug.h"
#include "msvcrt.h"
#include "cppexcept.h"
#include "mtdll.h"
34
#include "cxx.h"
35 36

WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
37

38 39 40 41 42 43
struct __type_info_node
{
    void *memPtr;
    struct __type_info_node* next;
};

44 45 46
typedef exception bad_cast;
typedef exception bad_typeid;
typedef exception __non_rtti_object;
47

48 49 50 51 52 53
extern const vtable_ptr MSVCRT_exception_vtable;
extern const vtable_ptr MSVCRT_bad_typeid_vtable;
extern const vtable_ptr MSVCRT_bad_cast_vtable;
extern const vtable_ptr MSVCRT___non_rtti_object_vtable;
extern const vtable_ptr MSVCRT_type_info_vtable;

54 55 56 57 58 59
/* get the vtable pointer for a C++ object */
static inline const vtable_ptr *get_vtable( void *obj )
{
    return *(const vtable_ptr **)obj;
}

60 61 62 63 64
static inline const rtti_object_locator *get_obj_locator( void *cppobj )
{
    const vtable_ptr *vtable = get_vtable( cppobj );
    return (const rtti_object_locator *)vtable[-1];
}
65

66
#ifndef __x86_64__
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
static void dump_obj_locator( const rtti_object_locator *ptr )
{
    int i;
    const rtti_object_hierarchy *h = ptr->type_hierarchy;

    TRACE( "%p: sig=%08x base_offset=%08x flags=%08x type=%p %s hierarchy=%p\n",
           ptr, ptr->signature, ptr->base_class_offset, ptr->flags,
           ptr->type_descriptor, dbgstr_type_info(ptr->type_descriptor), ptr->type_hierarchy );
    TRACE( "  hierarchy: sig=%08x attr=%08x len=%d base classes=%p\n",
           h->signature, h->attributes, h->array_len, h->base_classes );
    for (i = 0; i < h->array_len; i++)
    {
        TRACE( "    base class %p: num %d off %d,%d,%d attr %08x type %p %s\n",
               h->base_classes->bases[i],
               h->base_classes->bases[i]->num_base_classes,
               h->base_classes->bases[i]->offsets.this_offset,
               h->base_classes->bases[i]->offsets.vbase_descr,
               h->base_classes->bases[i]->offsets.vbase_offset,
               h->base_classes->bases[i]->attributes,
               h->base_classes->bases[i]->type_descriptor,
               dbgstr_type_info(h->base_classes->bases[i]->type_descriptor) );
    }
}

91 92 93
#else

static void dump_obj_locator( const rtti_object_locator *ptr )
94 95
{
    int i;
96
    char *base = ptr->signature == 0 ? RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator;
97
    const rtti_object_hierarchy *h = (const rtti_object_hierarchy*)(base + ptr->type_hierarchy);
98 99 100 101 102 103 104 105 106
    const type_info *type_descriptor = (const type_info*)(base + ptr->type_descriptor);

    TRACE( "%p: sig=%08x base_offset=%08x flags=%08x type=%p %s hierarchy=%p\n",
            ptr, ptr->signature, ptr->base_class_offset, ptr->flags,
            type_descriptor, dbgstr_type_info(type_descriptor), h );
    TRACE( "  hierarchy: sig=%08x attr=%08x len=%d base classes=%p\n",
            h->signature, h->attributes, h->array_len, base + h->base_classes );
    for (i = 0; i < h->array_len; i++)
    {
107 108
        const rtti_base_descriptor *bases = (rtti_base_descriptor*)(base +
                ((const rtti_base_array*)(base + h->base_classes))->bases[i]);
109 110 111 112 113 114 115 116 117 118 119 120 121 122

        TRACE( "    base class %p: num %d off %d,%d,%d attr %08x type %p %s\n",
                bases,
                bases->num_base_classes,
                bases->offsets.this_offset,
                bases->offsets.vbase_descr,
                bases->offsets.vbase_offset,
                bases->attributes,
                base + bases->type_descriptor,
                dbgstr_type_info((const type_info*)(base + bases->type_descriptor)) );
    }
}
#endif

123
/* Internal common ctor for exception */
124
static void EXCEPTION_ctor(exception *_this, const char** name)
125 126 127 128
{
  _this->vtable = &MSVCRT_exception_vtable;
  if (*name)
  {
129
    unsigned int name_len = strlen(*name) + 1;
130 131 132 133 134 135 136 137 138 139
    _this->name = MSVCRT_malloc(name_len);
    memcpy(_this->name, *name, name_len);
    _this->do_free = TRUE;
  }
  else
  {
    _this->name = NULL;
    _this->do_free = FALSE;
  }
}
140

141
/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
142
 *		??0exception@@QAE@ABQBD@Z (MSVCRT.@)
143
 */
144
DEFINE_THISCALL_WRAPPER(MSVCRT_exception_ctor,8)
145
exception * __thiscall MSVCRT_exception_ctor(exception * _this, const char ** name)
146
{
147 148
  TRACE("(%p,%s)\n", _this, *name);
  EXCEPTION_ctor(_this, name);
149
  return _this;
150 151
}

152 153 154 155
/******************************************************************
 *		??0exception@@QAE@ABQBDH@Z (MSVCRT.@)
 */
DEFINE_THISCALL_WRAPPER(MSVCRT_exception_ctor_noalloc,12)
156
exception * __thiscall MSVCRT_exception_ctor_noalloc(exception * _this, char ** name, int noalloc)
157 158 159 160 161 162 163 164
{
  TRACE("(%p,%s)\n", _this, *name);
  _this->vtable = &MSVCRT_exception_vtable;
  _this->name = *name;
  _this->do_free = FALSE;
  return _this;
}

165
/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
166
 *		??0exception@@QAE@ABV0@@Z (MSVCRT.@)
167
 */
168
DEFINE_THISCALL_WRAPPER(MSVCRT_exception_copy_ctor,8)
169
exception * __thiscall MSVCRT_exception_copy_ctor(exception * _this, const exception * rhs)
170
{
171 172 173
  TRACE("(%p,%p)\n", _this, rhs);

  if (!rhs->do_free)
174
  {
175 176 177
    _this->vtable = &MSVCRT_exception_vtable;
    _this->name = rhs->name;
    _this->do_free = FALSE;
178
  }
179 180 181
  else
    EXCEPTION_ctor(_this, (const char**)&rhs->name);
  TRACE("name = %s\n", _this->name);
182
  return _this;
183 184 185
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
186
 *		??0exception@@QAE@XZ (MSVCRT.@)
187
 */
188
DEFINE_THISCALL_WRAPPER(MSVCRT_exception_default_ctor,4)
189
exception * __thiscall MSVCRT_exception_default_ctor(exception * _this)
190
{
191 192 193 194
  static const char* empty = NULL;

  TRACE("(%p)\n", _this);
  EXCEPTION_ctor(_this, &empty);
195
  return _this;
196 197 198
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
199
 *		??1exception@@UAE@XZ (MSVCRT.@)
200
 */
201
DEFINE_THISCALL_WRAPPER(MSVCRT_exception_dtor,4)
202
void __thiscall MSVCRT_exception_dtor(exception * _this)
203
{
204 205 206
  TRACE("(%p)\n", _this);
  _this->vtable = &MSVCRT_exception_vtable;
  if (_this->do_free) MSVCRT_free(_this->name);
207 208 209
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
210
 *		??4exception@@QAEAAV0@ABV0@@Z (MSVCRT.@)
211
 */
212
DEFINE_THISCALL_WRAPPER(MSVCRT_exception_opequals,8)
213
exception * __thiscall MSVCRT_exception_opequals(exception * _this, const exception * rhs)
214
{
215
  TRACE("(%p %p)\n", _this, rhs);
216 217 218 219 220
  if (_this != rhs)
  {
      MSVCRT_exception_dtor(_this);
      MSVCRT_exception_copy_ctor(_this, rhs);
  }
221
  TRACE("name = %s\n", _this->name);
222 223 224 225
  return _this;
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
226
 *		??_Eexception@@UAEPAXI@Z (MSVCRT.@)
227
 */
228
DEFINE_THISCALL_WRAPPER(MSVCRT_exception_vector_dtor,8)
229
void * __thiscall MSVCRT_exception_vector_dtor(exception * _this, unsigned int flags)
230
{
231
    TRACE("(%p %x)\n", _this, flags);
232 233 234
    if (flags & 2)
    {
        /* we have an array, with the number of elements stored before the first object */
235
        INT_PTR i, *ptr = (INT_PTR *)_this - 1;
236 237 238 239 240 241 242 243 244 245

        for (i = *ptr - 1; i >= 0; i--) MSVCRT_exception_dtor(_this + i);
        MSVCRT_operator_delete(ptr);
    }
    else
    {
        MSVCRT_exception_dtor(_this);
        if (flags & 1) MSVCRT_operator_delete(_this);
    }
    return _this;
246 247 248
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
249
 *		??_Gexception@@UAEPAXI@Z (MSVCRT.@)
250
 */
251
DEFINE_THISCALL_WRAPPER(MSVCRT_exception_scalar_dtor,8)
252
void * __thiscall MSVCRT_exception_scalar_dtor(exception * _this, unsigned int flags)
253
{
254
    TRACE("(%p %x)\n", _this, flags);
255 256 257
    MSVCRT_exception_dtor(_this);
    if (flags & 1) MSVCRT_operator_delete(_this);
    return _this;
258 259 260
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
261
 *		?what@exception@@UBEPBDXZ (MSVCRT.@)
262
 */
263
DEFINE_THISCALL_WRAPPER(MSVCRT_what_exception,4)
264
const char * __thiscall MSVCRT_what_exception(exception * _this)
265
{
266
  TRACE("(%p) returning %s\n", _this, _this->name);
267
  return _this->name ? _this->name : "Unknown exception";
268 269 270
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
271
 *		??0bad_typeid@@QAE@ABV0@@Z (MSVCRT.@)
272
 */
273
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_copy_ctor,8)
274
bad_typeid * __thiscall MSVCRT_bad_typeid_copy_ctor(bad_typeid * _this, const bad_typeid * rhs)
275
{
276 277 278
  TRACE("(%p %p)\n", _this, rhs);
  MSVCRT_exception_copy_ctor(_this, rhs);
  _this->vtable = &MSVCRT_bad_typeid_vtable;
279
  return _this;
280 281 282
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
283
 *		??0bad_typeid@@QAE@PBD@Z (MSVCRT.@)
284
 */
285
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_ctor,8)
286
bad_typeid * __thiscall MSVCRT_bad_typeid_ctor(bad_typeid * _this, const char * name)
287
{
288 289 290
  TRACE("(%p %s)\n", _this, name);
  EXCEPTION_ctor(_this, &name);
  _this->vtable = &MSVCRT_bad_typeid_vtable;
291
  return _this;
292 293
}

294 295 296 297
/******************************************************************
 *		??_Fbad_typeid@@QAEXXZ (MSVCRT.@)
 */
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_default_ctor,4)
298
bad_typeid * __thiscall MSVCRT_bad_typeid_default_ctor(bad_typeid * _this)
299 300 301 302
{
  return MSVCRT_bad_typeid_ctor( _this, "bad typeid" );
}

303
/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
304
 *		??1bad_typeid@@UAE@XZ (MSVCRT.@)
305
 */
306
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_dtor,4)
307
void __thiscall MSVCRT_bad_typeid_dtor(bad_typeid * _this)
308
{
309 310
  TRACE("(%p)\n", _this);
  MSVCRT_exception_dtor(_this);
311 312 313
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
314
 *		??4bad_typeid@@QAEAAV0@ABV0@@Z (MSVCRT.@)
315
 */
316
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_opequals,8)
317
bad_typeid * __thiscall MSVCRT_bad_typeid_opequals(bad_typeid * _this, const bad_typeid * rhs)
318
{
319 320
  TRACE("(%p %p)\n", _this, rhs);
  MSVCRT_exception_opequals(_this, rhs);
321 322 323
  return _this;
}

324 325 326
/******************************************************************
 *              ??_Ebad_typeid@@UAEPAXI@Z (MSVCRT.@)
 */
327
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_vector_dtor,8)
328
void * __thiscall MSVCRT_bad_typeid_vector_dtor(bad_typeid * _this, unsigned int flags)
329
{
330
    TRACE("(%p %x)\n", _this, flags);
331 332 333
    if (flags & 2)
    {
        /* we have an array, with the number of elements stored before the first object */
334
        INT_PTR i, *ptr = (INT_PTR *)_this - 1;
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349

        for (i = *ptr - 1; i >= 0; i--) MSVCRT_bad_typeid_dtor(_this + i);
        MSVCRT_operator_delete(ptr);
    }
    else
    {
        MSVCRT_bad_typeid_dtor(_this);
        if (flags & 1) MSVCRT_operator_delete(_this);
    }
    return _this;
}

/******************************************************************
 *		??_Gbad_typeid@@UAEPAXI@Z (MSVCRT.@)
 */
350
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_typeid_scalar_dtor,8)
351
void * __thiscall MSVCRT_bad_typeid_scalar_dtor(bad_typeid * _this, unsigned int flags)
352
{
353
    TRACE("(%p %x)\n", _this, flags);
354 355 356 357 358
    MSVCRT_bad_typeid_dtor(_this);
    if (flags & 1) MSVCRT_operator_delete(_this);
    return _this;
}

359
/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
360
 *		??0__non_rtti_object@@QAE@ABV0@@Z (MSVCRT.@)
361
 */
362
DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_copy_ctor,8)
363
__non_rtti_object * __thiscall MSVCRT___non_rtti_object_copy_ctor(__non_rtti_object * _this,
364
                                                                 const __non_rtti_object * rhs)
365
{
366 367 368
  TRACE("(%p %p)\n", _this, rhs);
  MSVCRT_bad_typeid_copy_ctor(_this, rhs);
  _this->vtable = &MSVCRT___non_rtti_object_vtable;
369
  return _this;
370 371 372
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
373
 *		??0__non_rtti_object@@QAE@PBD@Z (MSVCRT.@)
374
 */
375
DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_ctor,8)
376
__non_rtti_object * __thiscall MSVCRT___non_rtti_object_ctor(__non_rtti_object * _this,
377
                                                            const char * name)
378
{
379 380 381
  TRACE("(%p %s)\n", _this, name);
  EXCEPTION_ctor(_this, &name);
  _this->vtable = &MSVCRT___non_rtti_object_vtable;
382
  return _this;
383 384 385
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
386
 *		??1__non_rtti_object@@UAE@XZ (MSVCRT.@)
387
 */
388
DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_dtor,4)
389
void __thiscall MSVCRT___non_rtti_object_dtor(__non_rtti_object * _this)
390
{
391 392
  TRACE("(%p)\n", _this);
  MSVCRT_bad_typeid_dtor(_this);
393 394 395
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
396
 *		??4__non_rtti_object@@QAEAAV0@ABV0@@Z (MSVCRT.@)
397
 */
398
DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_opequals,8)
399
__non_rtti_object * __thiscall MSVCRT___non_rtti_object_opequals(__non_rtti_object * _this,
400
                                                                const __non_rtti_object *rhs)
401
{
402 403
  TRACE("(%p %p)\n", _this, rhs);
  MSVCRT_bad_typeid_opequals(_this, rhs);
404 405 406 407
  return _this;
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
408
 *		??_E__non_rtti_object@@UAEPAXI@Z (MSVCRT.@)
409
 */
410
DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_vector_dtor,8)
411
void * __thiscall MSVCRT___non_rtti_object_vector_dtor(__non_rtti_object * _this, unsigned int flags)
412
{
413
    TRACE("(%p %x)\n", _this, flags);
414 415 416
    if (flags & 2)
    {
        /* we have an array, with the number of elements stored before the first object */
417
        INT_PTR i, *ptr = (INT_PTR *)_this - 1;
418 419 420 421 422 423 424 425 426 427

        for (i = *ptr - 1; i >= 0; i--) MSVCRT___non_rtti_object_dtor(_this + i);
        MSVCRT_operator_delete(ptr);
    }
    else
    {
        MSVCRT___non_rtti_object_dtor(_this);
        if (flags & 1) MSVCRT_operator_delete(_this);
    }
    return _this;
428 429 430
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
431
 *		??_G__non_rtti_object@@UAEPAXI@Z (MSVCRT.@)
432
 */
433
DEFINE_THISCALL_WRAPPER(MSVCRT___non_rtti_object_scalar_dtor,8)
434
void * __thiscall MSVCRT___non_rtti_object_scalar_dtor(__non_rtti_object * _this, unsigned int flags)
435
{
436
  TRACE("(%p %x)\n", _this, flags);
437 438 439
  MSVCRT___non_rtti_object_dtor(_this);
  if (flags & 1) MSVCRT_operator_delete(_this);
  return _this;
440 441 442
}

/******************************************************************
443
 *		??0bad_cast@@AAE@PBQBD@Z (MSVCRT.@)
Patrik Stridvall's avatar
Patrik Stridvall committed
444
 *		??0bad_cast@@QAE@ABQBD@Z (MSVCRT.@)
445
 */
446
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_ctor,8)
447
bad_cast * __thiscall MSVCRT_bad_cast_ctor(bad_cast * _this, const char ** name)
448
{
449 450 451
  TRACE("(%p %s)\n", _this, *name);
  EXCEPTION_ctor(_this, name);
  _this->vtable = &MSVCRT_bad_cast_vtable;
452
  return _this;
453 454 455
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
456
 *		??0bad_cast@@QAE@ABV0@@Z (MSVCRT.@)
457
 */
458
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_copy_ctor,8)
459
bad_cast * __thiscall MSVCRT_bad_cast_copy_ctor(bad_cast * _this, const bad_cast * rhs)
460
{
461 462 463
  TRACE("(%p %p)\n", _this, rhs);
  MSVCRT_exception_copy_ctor(_this, rhs);
  _this->vtable = &MSVCRT_bad_cast_vtable;
464
  return _this;
465 466
}

467 468 469 470
/******************************************************************
 *		??0bad_cast@@QAE@PBD@Z (MSVCRT.@)
 */
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_ctor_charptr,8)
471
bad_cast * __thiscall MSVCRT_bad_cast_ctor_charptr(bad_cast * _this, const char * name)
472 473 474 475 476 477 478 479 480 481 482
{
  TRACE("(%p %s)\n", _this, name);
  EXCEPTION_ctor(_this, &name);
  _this->vtable = &MSVCRT_bad_cast_vtable;
  return _this;
}

/******************************************************************
 *		??_Fbad_cast@@QAEXXZ (MSVCRT.@)
 */
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_default_ctor,4)
483
bad_cast * __thiscall MSVCRT_bad_cast_default_ctor(bad_cast * _this)
484 485 486 487
{
  return MSVCRT_bad_cast_ctor_charptr( _this, "bad cast" );
}

488
/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
489
 *		??1bad_cast@@UAE@XZ (MSVCRT.@)
490
 */
491
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_dtor,4)
492
void __thiscall MSVCRT_bad_cast_dtor(bad_cast * _this)
493
{
494 495
  TRACE("(%p)\n", _this);
  MSVCRT_exception_dtor(_this);
496 497 498
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
499
 *		??4bad_cast@@QAEAAV0@ABV0@@Z (MSVCRT.@)
500
 */
501
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_opequals,8)
502
bad_cast * __thiscall MSVCRT_bad_cast_opequals(bad_cast * _this, const bad_cast * rhs)
503
{
504 505
  TRACE("(%p %p)\n", _this, rhs);
  MSVCRT_exception_opequals(_this, rhs);
506 507 508 509 510 511
  return _this;
}

/******************************************************************
 *              ??_Ebad_cast@@UAEPAXI@Z (MSVCRT.@)
 */
512
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_vector_dtor,8)
513
void * __thiscall MSVCRT_bad_cast_vector_dtor(bad_cast * _this, unsigned int flags)
514
{
515
    TRACE("(%p %x)\n", _this, flags);
516 517 518
    if (flags & 2)
    {
        /* we have an array, with the number of elements stored before the first object */
519
        INT_PTR i, *ptr = (INT_PTR *)_this - 1;
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

        for (i = *ptr - 1; i >= 0; i--) MSVCRT_bad_cast_dtor(_this + i);
        MSVCRT_operator_delete(ptr);
    }
    else
    {
        MSVCRT_bad_cast_dtor(_this);
        if (flags & 1) MSVCRT_operator_delete(_this);
    }
    return _this;
}

/******************************************************************
 *		??_Gbad_cast@@UAEPAXI@Z (MSVCRT.@)
 */
535
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_cast_scalar_dtor,8)
536
void * __thiscall MSVCRT_bad_cast_scalar_dtor(bad_cast * _this, unsigned int flags)
537
{
538
  TRACE("(%p %x)\n", _this, flags);
539 540
  MSVCRT_bad_cast_dtor(_this);
  if (flags & 1) MSVCRT_operator_delete(_this);
541 542 543 544
  return _this;
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
545
 *		??8type_info@@QBEHABV0@@Z (MSVCRT.@)
546
 */
547
DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opequals_equals,8)
548
int __thiscall MSVCRT_type_info_opequals_equals(type_info * _this, const type_info * rhs)
549
{
550 551
    int ret = !strcmp(_this->mangled + 1, rhs->mangled + 1);
    TRACE("(%p %p) returning %d\n", _this, rhs, ret);
552
    return ret;
553 554 555
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
556
 *		??9type_info@@QBEHABV0@@Z (MSVCRT.@)
557
 */
558
DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opnot_equals,8)
559
int __thiscall MSVCRT_type_info_opnot_equals(type_info * _this, const type_info * rhs)
560
{
561 562
    int ret = !!strcmp(_this->mangled + 1, rhs->mangled + 1);
    TRACE("(%p %p) returning %d\n", _this, rhs, ret);
563 564 565 566 567 568
    return ret;
}

/******************************************************************
 *		?before@type_info@@QBEHABV1@@Z (MSVCRT.@)
 */
569
DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_before,8)
570
int __thiscall MSVCRT_type_info_before(type_info * _this, const type_info * rhs)
571
{
572 573
    int ret = strcmp(_this->mangled + 1, rhs->mangled + 1) < 0;
    TRACE("(%p %p) returning %d\n", _this, rhs, ret);
574
    return ret;
575 576 577
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
578
 *		??1type_info@@UAE@XZ (MSVCRT.@)
579
 */
580
DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_dtor,4)
581
void __thiscall MSVCRT_type_info_dtor(type_info * _this)
582
{
583
  TRACE("(%p)\n", _this);
584
  MSVCRT_free(_this->name);
585 586 587
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
588
 *		?name@type_info@@QBEPBDXZ (MSVCRT.@)
589
 */
590
DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_name,4)
591
const char * __thiscall MSVCRT_type_info_name(type_info * _this)
592
{
593 594 595
  if (!_this->name)
  {
    /* Create and set the demangled name */
André Hentschel's avatar
André Hentschel committed
596
    /* Note: mangled name in type_info struct always starts with a '.', while
597 598 599 600
     * it isn't valid for mangled name.
     * Is this '.' really part of the mangled name, or has it some other meaning ?
     */
    char* name = __unDName(0, _this->mangled + 1, 0,
601
                           MSVCRT_malloc, MSVCRT_free, UNDNAME_NO_ARGUMENTS | UNDNAME_32_BIT_DECODE);
602 603 604 605 606
    if (name)
    {
      unsigned int len = strlen(name);

      /* It seems _unDName may leave blanks at the end of the demangled name */
607
      while (len && name[--len] == ' ')
608 609
        name[len] = '\0';

610
      if (InterlockedCompareExchangePointer((void**)&_this->name, name, NULL))
611 612 613 614 615 616 617
      {
        /* Another thread set this member since we checked above - use it */
        MSVCRT_free(name);
      }
    }
  }
  TRACE("(%p) returning %s\n", _this, _this->name);
618 619 620 621
  return _this->name;
}

/******************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
622
 *		?raw_name@type_info@@QBEPBDXZ (MSVCRT.@)
623
 */
624
DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_raw_name,4)
625
const char * __thiscall MSVCRT_type_info_raw_name(type_info * _this)
626
{
627 628 629 630 631
  TRACE("(%p) returning %s\n", _this, _this->mangled);
  return _this->mangled;
}

/* Unexported */
632
DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_vector_dtor,8)
633
void * __thiscall MSVCRT_type_info_vector_dtor(type_info * _this, unsigned int flags)
634 635 636 637 638
{
    TRACE("(%p %x)\n", _this, flags);
    if (flags & 2)
    {
        /* we have an array, with the number of elements stored before the first object */
639
        INT_PTR i, *ptr = (INT_PTR *)_this - 1;
640 641 642 643 644 645 646 647 648 649

        for (i = *ptr - 1; i >= 0; i--) MSVCRT_type_info_dtor(_this + i);
        MSVCRT_operator_delete(ptr);
    }
    else
    {
        MSVCRT_type_info_dtor(_this);
        if (flags & 1) MSVCRT_operator_delete(_this);
    }
    return _this;
650 651
}

652 653 654
#ifndef __GNUC__
void __asm_dummy_vtables(void) {
#endif
655

656 657 658 659 660
__ASM_VTABLE(type_info,
        VTABLE_ADD_FUNC(MSVCRT_type_info_vector_dtor));
__ASM_VTABLE(exception,
        VTABLE_ADD_FUNC(MSVCRT_exception_vector_dtor)
        VTABLE_ADD_FUNC(MSVCRT_what_exception));
661 662 663 664 665
#if _MSVCR_VER >= 80
__ASM_VTABLE(exception_old,
        VTABLE_ADD_FUNC(MSVCRT_exception_vector_dtor)
        VTABLE_ADD_FUNC(MSVCRT_what_exception));
#endif
666 667 668 669 670 671 672 673 674
__ASM_VTABLE(bad_typeid,
        VTABLE_ADD_FUNC(MSVCRT_bad_typeid_vector_dtor)
        VTABLE_ADD_FUNC(MSVCRT_what_exception));
__ASM_VTABLE(bad_cast,
        VTABLE_ADD_FUNC(MSVCRT_bad_cast_vector_dtor)
        VTABLE_ADD_FUNC(MSVCRT_what_exception));
__ASM_VTABLE(__non_rtti_object,
        VTABLE_ADD_FUNC(MSVCRT___non_rtti_object_vector_dtor)
        VTABLE_ADD_FUNC(MSVCRT_what_exception));
675

676 677 678
#ifndef __GNUC__
}
#endif
679

680
DEFINE_RTTI_DATA0( type_info, 0, ".?AVtype_info@@" )
681 682 683 684 685 686 687
#if _MSVCR_VER >= 80
DEFINE_RTTI_DATA0( exception, 0, ".?AVexception@std@@" )
DEFINE_RTTI_DATA0( exception_old, 0, ".?AVexception@@" )
DEFINE_RTTI_DATA1( bad_typeid, 0, &exception_rtti_base_descriptor, ".?AVbad_typeid@std@@" )
DEFINE_RTTI_DATA1( bad_cast, 0, &exception_rtti_base_descriptor, ".?AVbad_cast@std@@" )
DEFINE_RTTI_DATA2( __non_rtti_object, 0, &bad_typeid_rtti_base_descriptor, &exception_rtti_base_descriptor, ".?AV__non_rtti_object@std@@" )
#else
688 689 690 691
DEFINE_RTTI_DATA0( exception, 0, ".?AVexception@@" )
DEFINE_RTTI_DATA1( bad_typeid, 0, &exception_rtti_base_descriptor, ".?AVbad_typeid@@" )
DEFINE_RTTI_DATA1( bad_cast, 0, &exception_rtti_base_descriptor, ".?AVbad_cast@@" )
DEFINE_RTTI_DATA2( __non_rtti_object, 0, &bad_typeid_rtti_base_descriptor, &exception_rtti_base_descriptor, ".?AV__non_rtti_object@@" )
692
#endif
693 694 695 696 697

DEFINE_EXCEPTION_TYPE_INFO( exception, 0, NULL, NULL )
DEFINE_EXCEPTION_TYPE_INFO( bad_typeid, 1, &exception_cxx_type_info, NULL )
DEFINE_EXCEPTION_TYPE_INFO( bad_cast, 1, &exception_cxx_type_info, NULL )
DEFINE_EXCEPTION_TYPE_INFO( __non_rtti_object, 2, &bad_typeid_cxx_type_info, &exception_cxx_type_info )
698

699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
#if _MSVCR_VER >= 80
typedef exception bad_alloc;
extern const vtable_ptr MSVCRT_bad_alloc_vtable;

static void bad_alloc_ctor(bad_alloc *this, const char **name)
{
    MSVCRT_exception_ctor(this, name);
    this->vtable = &MSVCRT_bad_alloc_vtable;
}

/* bad_alloc class implementation */
DEFINE_THISCALL_WRAPPER(MSVCRT_bad_alloc_copy_ctor,8)
bad_alloc * __thiscall MSVCRT_bad_alloc_copy_ctor(bad_alloc * _this, const bad_alloc * rhs)
{
    TRACE("(%p %p)\n", _this, rhs);
    MSVCRT_exception_copy_ctor(_this, rhs);
    _this->vtable = &MSVCRT_bad_alloc_vtable;
    return _this;
}

DEFINE_THISCALL_WRAPPER(MSVCRT_bad_alloc_dtor,4)
void __thiscall MSVCRT_bad_alloc_dtor(bad_alloc * _this)
{
    TRACE("(%p)\n", _this);
    MSVCRT_exception_dtor(_this);
}

__ASM_VTABLE(bad_alloc,
        VTABLE_ADD_FUNC(MSVCRT_exception_vector_dtor)
        VTABLE_ADD_FUNC(MSVCRT_what_exception));
DEFINE_RTTI_DATA1( bad_alloc, 0, &exception_rtti_base_descriptor, ".?AVbad_alloc@std@@" )
DEFINE_EXCEPTION_TYPE_INFO( bad_alloc, 1, &exception_cxx_type_info, NULL )

void throw_bad_alloc(const char *str)
{
    bad_alloc e;
    bad_alloc_ctor(&e, &str);
    _CxxThrowException(&e, &bad_alloc_exception_type);
}
#endif

740 741 742 743 744
void msvcrt_init_exception(void *base)
{
#ifdef __x86_64__
    init_type_info_rtti(base);
    init_exception_rtti(base);
745 746
#if _MSVCR_VER >= 80
    init_exception_old_rtti(base);
747
    init_bad_alloc_rtti(base);
748
#endif
749 750 751
    init_bad_typeid_rtti(base);
    init_bad_cast_rtti(base);
    init___non_rtti_object_rtti(base);
752 753 754 755 756

    init_exception_cxx(base);
    init_bad_typeid_cxx(base);
    init_bad_cast_cxx(base);
    init___non_rtti_object_cxx(base);
757 758 759
#if _MSVCR_VER >= 80
    init_bad_alloc_cxx(base);
#endif
760 761 762
#endif
}

763 764 765

/******************************************************************
 *		?set_terminate@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
766 767 768 769 770 771 772 773
 *
 * Install a handler to be called when terminate() is called.
 *
 * PARAMS
 *  func [I] Handler function to install
 *
 * RETURNS
 *  The previously installed handler function, if any.
774
 */
775
MSVCRT_terminate_function CDECL MSVCRT_set_terminate(MSVCRT_terminate_function func)
776
{
777 778
    thread_data_t *data = msvcrt_get_thread_data();
    MSVCRT_terminate_function previous = data->terminate_handler;
779 780 781 782 783
    TRACE("(%p) returning %p\n",func,previous);
    data->terminate_handler = func;
    return previous;
}

784 785 786 787 788 789 790 791 792 793
/******************************************************************
 *              _get_terminate (MSVCRT.@)
 */
MSVCRT_terminate_function CDECL MSVCRT__get_terminate(void)
{
    thread_data_t *data = msvcrt_get_thread_data();
    TRACE("returning %p\n", data->terminate_handler);
    return data->terminate_handler;
}

794 795
/******************************************************************
 *		?set_unexpected@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
796 797 798 799 800 801 802 803
 *
 * Install a handler to be called when unexpected() is called.
 *
 * PARAMS
 *  func [I] Handler function to install
 *
 * RETURNS
 *  The previously installed handler function, if any.
804
 */
805
MSVCRT_unexpected_function CDECL MSVCRT_set_unexpected(MSVCRT_unexpected_function func)
806
{
807 808
    thread_data_t *data = msvcrt_get_thread_data();
    MSVCRT_unexpected_function previous = data->unexpected_handler;
809 810 811 812 813
    TRACE("(%p) returning %p\n",func,previous);
    data->unexpected_handler = func;
    return previous;
}

814 815 816 817 818 819 820 821 822 823
/******************************************************************
 *              _get_unexpected (MSVCRT.@)
 */
MSVCRT_unexpected_function CDECL MSVCRT__get_unexpected(void)
{
    thread_data_t *data = msvcrt_get_thread_data();
    TRACE("returning %p\n", data->unexpected_handler);
    return data->unexpected_handler;
}

824 825 826
/******************************************************************
 *              ?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z  (MSVCRT.@)
 */
827
MSVCRT__se_translator_function CDECL MSVCRT__set_se_translator(MSVCRT__se_translator_function func)
828
{
829 830
    thread_data_t *data = msvcrt_get_thread_data();
    MSVCRT__se_translator_function previous = data->se_translator;
831 832 833 834 835 836 837
    TRACE("(%p) returning %p\n",func,previous);
    data->se_translator = func;
    return previous;
}

/******************************************************************
 *		?terminate@@YAXXZ (MSVCRT.@)
838 839 840 841 842 843 844 845 846 847
 *
 * Default handler for an unhandled exception.
 *
 * PARAMS
 *  None.
 *
 * RETURNS
 *  This function does not return. Either control resumes from any
 *  handler installed by calling set_terminate(), or (by default) abort()
 *  is called.
848
 */
849
void CDECL MSVCRT_terminate(void)
850
{
851
    thread_data_t *data = msvcrt_get_thread_data();
852 853 854 855 856 857 858
    if (data->terminate_handler) data->terminate_handler();
    MSVCRT_abort();
}

/******************************************************************
 *		?unexpected@@YAXXZ (MSVCRT.@)
 */
859
void CDECL MSVCRT_unexpected(void)
860
{
861
    thread_data_t *data = msvcrt_get_thread_data();
862 863 864
    if (data->unexpected_handler) data->unexpected_handler();
    MSVCRT_terminate();
}
865

866

867 868
/******************************************************************
 *		__RTtypeid (MSVCRT.@)
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
 *
 * Retrieve the Run Time Type Information (RTTI) for a C++ object.
 *
 * PARAMS
 *  cppobj [I] C++ object to get type information for.
 *
 * RETURNS
 *  Success: A type_info object describing cppobj.
 *  Failure: If the object to be cast has no RTTI, a __non_rtti_object
 *           exception is thrown. If cppobj is NULL, a bad_typeid exception
 *           is thrown. In either case, this function does not return.
 *
 * NOTES
 *  This function is usually called by compiler generated code as a result
 *  of using one of the C++ dynamic cast statements.
884
 */
885
#ifndef __x86_64__
886
const type_info* CDECL MSVCRT___RTtypeid(void *cppobj)
887
{
888
    const type_info *ret;
889 890 891

    if (!cppobj)
    {
892 893 894 895
        bad_typeid e;
        MSVCRT_bad_typeid_ctor( &e, "Attempted a typeid of NULL pointer!" );
        _CxxThrowException( &e, &bad_typeid_exception_type );
        return NULL;
896
    }
897 898

    __TRY
899
    {
900 901
        const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
        ret = obj_locator->type_descriptor;
902
    }
903
    __EXCEPT_PAGE_FAULT
904 905 906
    {
        __non_rtti_object e;
        MSVCRT___non_rtti_object_ctor( &e, "Bad read pointer - no RTTI data!" );
907
        _CxxThrowException( &e, &__non_rtti_object_exception_type );
908 909 910 911
        return NULL;
    }
    __ENDTRY
    return ret;
912 913
}

914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
#else

const type_info* CDECL MSVCRT___RTtypeid(void *cppobj)
{
    const type_info *ret;

    if (!cppobj)
    {
        bad_typeid e;
        MSVCRT_bad_typeid_ctor( &e, "Attempted a typeid of NULL pointer!" );
        _CxxThrowException( &e, &bad_typeid_exception_type );
        return NULL;
    }

    __TRY
    {
930 931 932
        const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
        char *base;

933
        if(obj_locator->signature == 0)
934
            base = RtlPcToFileHeader((void*)obj_locator, (void**)&base);
935
        else
936 937 938
            base = (char*)obj_locator - obj_locator->object_locator;

        ret = (type_info*)(base + obj_locator->type_descriptor);
939 940 941 942 943
    }
    __EXCEPT_PAGE_FAULT
    {
        __non_rtti_object e;
        MSVCRT___non_rtti_object_ctor( &e, "Bad read pointer - no RTTI data!" );
944
        _CxxThrowException( &e, &__non_rtti_object_exception_type );
945 946 947 948 949 950 951
        return NULL;
    }
    __ENDTRY
    return ret;
}
#endif

952 953
/******************************************************************
 *		__RTDynamicCast (MSVCRT.@)
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
 *
 * Dynamically cast a C++ object to one of its base classes.
 *
 * PARAMS
 *  cppobj   [I] Any C++ object to cast
 *  unknown  [I] Reserved, set to 0
 *  src      [I] type_info object describing cppobj
 *  dst      [I] type_info object describing the base class to cast to
 *  do_throw [I] TRUE = throw an exception if the cast fails, FALSE = don't
 *
 * RETURNS
 *  Success: The address of cppobj, cast to the object described by dst.
 *  Failure: NULL, If the object to be cast has no RTTI, or dst is not a
 *           valid cast for cppobj. If do_throw is TRUE, a bad_cast exception
 *           is thrown and this function does not return.
 *
 * NOTES
 *  This function is usually called by compiler generated code as a result
 *  of using one of the C++ dynamic cast statements.
973
 */
974
#ifndef __x86_64__
975 976 977
void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown,
                                   type_info *src, type_info *dst,
                                   int do_throw)
978
{
979
    void *ret;
980

981
    if (!cppobj) return NULL;
982

983 984
    TRACE("obj: %p unknown: %d src: %p %s dst: %p %s do_throw: %d)\n",
          cppobj, unknown, src, dbgstr_type_info(src), dst, dbgstr_type_info(dst), do_throw);
985

986 987 988 989 990
    /* To cast an object at runtime:
     * 1.Find out the true type of the object from the typeinfo at vtable[-1]
     * 2.Search for the destination type in the class hierarchy
     * 3.If destination type is found, return base object address + dest offset
     *   Otherwise, fail the cast
991 992
     *
     * FIXME: the unknown parameter doesn't seem to be used for anything
993 994 995 996 997 998
     */
    __TRY
    {
        int i;
        const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
        const rtti_object_hierarchy *obj_bases = obj_locator->type_hierarchy;
999
        const rtti_base_descriptor * const* base_desc = obj_bases->base_classes->bases;
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026

        if (TRACE_ON(msvcrt)) dump_obj_locator(obj_locator);

        ret = NULL;
        for (i = 0; i < obj_bases->array_len; i++)
        {
            const type_info *typ = base_desc[i]->type_descriptor;

            if (!strcmp(typ->mangled, dst->mangled))
            {
                /* compute the correct this pointer for that base class */
                void *this_ptr = (char *)cppobj - obj_locator->base_class_offset;
                ret = get_this_pointer( &base_desc[i]->offsets, this_ptr );
                break;
            }
        }
        /* VC++ sets do_throw to 1 when the result of a dynamic_cast is assigned
         * to a reference, since references cannot be NULL.
         */
        if (!ret && do_throw)
        {
            const char *msg = "Bad dynamic_cast!";
            bad_cast e;
            MSVCRT_bad_cast_ctor( &e, &msg );
            _CxxThrowException( &e, &bad_cast_exception_type );
        }
    }
1027
    __EXCEPT_PAGE_FAULT
1028 1029 1030
    {
        __non_rtti_object e;
        MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" );
1031
        _CxxThrowException( &e, &__non_rtti_object_exception_type );
1032 1033 1034 1035
        return NULL;
    }
    __ENDTRY
    return ret;
1036 1037
}

1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
#else

void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown,
        type_info *src, type_info *dst,
        int do_throw)
{
    void *ret;

    if (!cppobj) return NULL;

    TRACE("obj: %p unknown: %d src: %p %s dst: %p %s do_throw: %d)\n",
            cppobj, unknown, src, dbgstr_type_info(src), dst, dbgstr_type_info(dst), do_throw);

    __TRY
    {
        int i;
        const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
1055 1056 1057 1058 1059
        const rtti_object_hierarchy *obj_bases;
        const rtti_base_array *base_array;
        char *base;

        if (TRACE_ON(msvcrt)) dump_obj_locator(obj_locator);
1060 1061

        if(obj_locator->signature == 0)
1062
            base = RtlPcToFileHeader((void*)obj_locator, (void**)&base);
1063 1064
        else
            base = (char*)obj_locator - obj_locator->object_locator;
1065

1066 1067
        obj_bases = (const rtti_object_hierarchy*)(base + obj_locator->type_hierarchy);
        base_array = (const rtti_base_array*)(base + obj_bases->base_classes);
1068

1069 1070
        ret = NULL;
        for (i = 0; i < obj_bases->array_len; i++)
1071
        {
1072 1073
            const rtti_base_descriptor *base_desc = (const rtti_base_descriptor*)(base + base_array->bases[i]);
            const type_info *typ = (const type_info*)(base + base_desc->type_descriptor);
1074

1075
            if (!strcmp(typ->mangled, dst->mangled))
1076
            {
1077 1078 1079
                void *this_ptr = (char *)cppobj - obj_locator->base_class_offset;
                ret = get_this_pointer( &base_desc->offsets, this_ptr );
                break;
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
            }
        }
        if (!ret && do_throw)
        {
            const char *msg = "Bad dynamic_cast!";
            bad_cast e;
            MSVCRT_bad_cast_ctor( &e, &msg );
            _CxxThrowException( &e, &bad_cast_exception_type );
        }
    }
    __EXCEPT_PAGE_FAULT
    {
        __non_rtti_object e;
        MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" );
1094
        _CxxThrowException( &e, &__non_rtti_object_exception_type );
1095 1096 1097 1098 1099 1100 1101
        return NULL;
    }
    __ENDTRY
    return ret;
}
#endif

1102 1103 1104

/******************************************************************
 *		__RTCastToVoid (MSVCRT.@)
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
 *
 * Dynamically cast a C++ object to a void*.
 *
 * PARAMS
 *  cppobj [I] The C++ object to cast
 *
 * RETURNS
 *  Success: The base address of the object as a void*.
 *  Failure: NULL, if cppobj is NULL or has no RTTI.
 *
 * NOTES
 *  This function is usually called by compiler generated code as a result
 *  of using one of the C++ dynamic cast statements.
1118
 */
1119
void* CDECL MSVCRT___RTCastToVoid(void *cppobj)
1120
{
1121
    void *ret;
1122

1123
    if (!cppobj) return NULL;
1124

1125 1126 1127 1128 1129
    __TRY
    {
        const rtti_object_locator *obj_locator = get_obj_locator( cppobj );
        ret = (char *)cppobj - obj_locator->base_class_offset;
    }
1130
    __EXCEPT_PAGE_FAULT
1131 1132 1133
    {
        __non_rtti_object e;
        MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" );
1134
        _CxxThrowException( &e, &__non_rtti_object_exception_type );
1135 1136 1137 1138
        return NULL;
    }
    __ENDTRY
    return ret;
1139
}
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153


/*********************************************************************
 *		_CxxThrowException (MSVCRT.@)
 */
void WINAPI _CxxThrowException( exception *object, const cxx_exception_type *type )
{
    ULONG_PTR args[3];

    args[0] = CXX_FRAME_MAGIC_VC6;
    args[1] = (ULONG_PTR)object;
    args[2] = (ULONG_PTR)type;
    RaiseException( CXX_EXCEPTION, EH_NONCONTINUABLE, 3, args );
}
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238

/*********************************************************************
 * ?_is_exception_typeof@@YAHABVtype_info@@PAU_EXCEPTION_POINTERS@@@Z
 * ?_is_exception_typeof@@YAHAEBVtype_info@@PEAU_EXCEPTION_POINTERS@@@Z
 */
#ifndef __x86_64__
int __cdecl _is_exception_typeof(const type_info *ti, EXCEPTION_POINTERS *ep)
{
    int ret = -1;

    TRACE("(%p %p)\n", ti, ep);

    __TRY
    {
        EXCEPTION_RECORD *rec = ep->ExceptionRecord;

        if (rec->ExceptionCode==CXX_EXCEPTION && rec->NumberParameters==3 &&
                (rec->ExceptionInformation[0]==CXX_FRAME_MAGIC_VC6 ||
                 rec->ExceptionInformation[0]==CXX_FRAME_MAGIC_VC7 ||
                 rec->ExceptionInformation[0]==CXX_FRAME_MAGIC_VC8))
        {
            const cxx_type_info_table *tit = ((cxx_exception_type*)rec->ExceptionInformation[2])->type_info_table;
            int i;

            for (i=0; i<tit->count; i++) {
                if (ti==tit->info[i]->type_info || !strcmp(ti->mangled, tit->info[i]->type_info->mangled))
                {
                    ret = 1;
                    break;
                }
            }

            if (i == tit->count)
                ret = 0;
        }
    }
    __EXCEPT_PAGE_FAULT
    __ENDTRY

    if(ret == -1)
        MSVCRT_terminate();
    return ret;
}
#else
int __cdecl _is_exception_typeof(const type_info *ti, EXCEPTION_POINTERS *ep)
{
    int ret = -1;

    TRACE("(%p %p)\n", ti, ep);

    __TRY
    {
        EXCEPTION_RECORD *rec = ep->ExceptionRecord;

        if (rec->ExceptionCode==CXX_EXCEPTION && rec->NumberParameters==4 &&
                (rec->ExceptionInformation[0]==CXX_FRAME_MAGIC_VC6 ||
                 rec->ExceptionInformation[0]==CXX_FRAME_MAGIC_VC7 ||
                 rec->ExceptionInformation[0]==CXX_FRAME_MAGIC_VC8))
        {
            const cxx_exception_type *et = (cxx_exception_type*)rec->ExceptionInformation[2];
            const cxx_type_info_table *tit = (const cxx_type_info_table*)(rec->ExceptionInformation[3]+et->type_info_table);
            int i;

            for (i=0; i<tit->count; i++) {
                const cxx_type_info *cti = (const cxx_type_info*)(rec->ExceptionInformation[3]+tit->info[i]);
                const type_info *except_ti = (const type_info*)(rec->ExceptionInformation[3]+cti->type_info);
                if (ti==except_ti || !strcmp(ti->mangled, except_ti->mangled))
                {
                    ret = 1;
                    break;
                }
            }

            if (i == tit->count)
                ret = 0;
        }
    }
    __EXCEPT_PAGE_FAULT
    __ENDTRY

    if(ret == -1)
        MSVCRT_terminate();
    return ret;
}
#endif
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256

/*********************************************************************
 * __clean_type_info_names_internal (MSVCR100.@)
 */
void CDECL __clean_type_info_names_internal(void *p)
{
    FIXME("(%p) stub\n", p);
}

/*********************************************************************
 * ?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z (MSVCR100.@)
 */
DEFINE_THISCALL_WRAPPER(type_info_name_internal_method,8)
const char * __thiscall type_info_name_internal_method(type_info * _this, struct __type_info_node *node)
{
    static int once;
    if (node && !once++) FIXME("type_info_node parameter ignored\n");

1257
    return MSVCRT_type_info_name(_this);
1258
}
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478

/* std::exception_ptr class helpers */
typedef struct
{
    EXCEPTION_RECORD *rec;
    int *ref; /* not binary compatible with native msvcr100 */
} exception_ptr;

/*********************************************************************
 * ?__ExceptionPtrCreate@@YAXPAX@Z
 * ?__ExceptionPtrCreate@@YAXPEAX@Z
 */
void __cdecl __ExceptionPtrCreate(exception_ptr *ep)
{
    TRACE("(%p)\n", ep);

    ep->rec = NULL;
    ep->ref = NULL;
}

#ifdef __i386__
static inline void call_dtor(const cxx_exception_type *type, void *func, void *object)
{
    __asm__ __volatile__("call *%0" : : "m" (func), "c" (object) : "eax", "edx", "memory");
}
#elif __x86_64__
static inline void call_dtor(const cxx_exception_type *type, unsigned int dtor, void *object)
{
    char *base = RtlPcToFileHeader((void*)type, (void**)&base);
    void (__cdecl *func)(void*) = (void*)(base + dtor);
    func(object);
}
#else
#define call_dtor(type, func, object) ((void (__cdecl*)(void*))(func))(object)
#endif

/*********************************************************************
 * ?__ExceptionPtrDestroy@@YAXPAX@Z
 * ?__ExceptionPtrDestroy@@YAXPEAX@Z
 */
void __cdecl __ExceptionPtrDestroy(exception_ptr *ep)
{
    TRACE("(%p)\n", ep);

    if (!ep->rec)
        return;

    if (!InterlockedDecrement(ep->ref))
    {
        if (ep->rec->ExceptionCode == CXX_EXCEPTION)
        {
            const cxx_exception_type *type = (void*)ep->rec->ExceptionInformation[2];
            void *obj = (void*)ep->rec->ExceptionInformation[1];

            if (type && type->destructor) call_dtor(type, type->destructor, obj);
            HeapFree(GetProcessHeap(), 0, obj);
        }

        HeapFree(GetProcessHeap(), 0, ep->rec);
        HeapFree(GetProcessHeap(), 0, ep->ref);
    }
}

/*********************************************************************
 * ?__ExceptionPtrCopy@@YAXPAXPBX@Z
 * ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z
 */
void __cdecl __ExceptionPtrCopy(exception_ptr *ep, const exception_ptr *copy)
{
    TRACE("(%p %p)\n", ep, copy);

    /* don't destroy object stored in ep */
    *ep = *copy;
    if (ep->ref)
        InterlockedIncrement(copy->ref);
}

/*********************************************************************
 * ?__ExceptionPtrRethrow@@YAXPBX@Z
 * ?__ExceptionPtrRethrow@@YAXPEBX@Z
 */
void __cdecl __ExceptionPtrRethrow(const exception_ptr *ep)
{
    TRACE("(%p)\n", ep);

    if (!ep->rec)
    {
        static const char *exception_msg = "bad exception";
        exception e;

        MSVCRT_exception_ctor(&e, &exception_msg);
        _CxxThrowException(&e, &exception_exception_type);
        return;
    }

    RaiseException(ep->rec->ExceptionCode, ep->rec->ExceptionFlags & (~EH_UNWINDING),
            ep->rec->NumberParameters, ep->rec->ExceptionInformation);
}

#ifdef __i386__
static inline void call_copy_ctor( void *func, void *this, void *src, int has_vbase )
{
    TRACE( "calling copy ctor %p object %p src %p\n", func, this, src );
    if (has_vbase)
        /* in that case copy ctor takes an extra bool indicating whether to copy the base class */
        __asm__ __volatile__("pushl $1; pushl %2; call *%0"
                             : : "m" (func), "c" (this), "m" (src) : "eax", "edx", "memory" );
    else
        __asm__ __volatile__("pushl %2; call *%0"
                             : : "m" (func), "c" (this), "m" (src) : "eax", "edx", "memory" );
}
#else
static inline void call_copy_ctor( void *func, void *this, void *src, int has_vbase )
{
    TRACE( "calling copy ctor %p object %p src %p\n", func, this, src );
    if (has_vbase)
        ((void (__cdecl*)(void*, void*, BOOL))func)(this, src, 1);
    else
        ((void (__cdecl*)(void*, void*))func)(this, src);
}
#endif

/*********************************************************************
 * ?__ExceptionPtrCurrentException@@YAXPAX@Z
 * ?__ExceptionPtrCurrentException@@YAXPEAX@Z
 */
#ifndef __x86_64__
void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep)
{
    EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record;

    TRACE("(%p)\n", ep);

    if (!rec)
    {
        ep->rec = NULL;
        ep->ref = NULL;
        return;
    }

    ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD));
    ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int));

    *ep->rec = *rec;
    *ep->ref = 1;

    if (ep->rec->ExceptionCode == CXX_EXCEPTION)
    {
        const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2];
        const cxx_type_info *ti;
        void **data, *obj;

        ti = et->type_info_table->info[0];
        data = HeapAlloc(GetProcessHeap(), 0, ti->size);

        obj = (void*)ep->rec->ExceptionInformation[1];
        if (ti->flags & CLASS_IS_SIMPLE_TYPE)
        {
            memcpy(data, obj, ti->size);
            if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data);
        }
        else if (ti->copy_ctor)
        {
            call_copy_ctor(ti->copy_ctor, data, get_this_pointer(&ti->offsets, obj),
                    ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS);
        }
        else
            memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size);
        ep->rec->ExceptionInformation[1] = (ULONG_PTR)data;
    }
    return;
}
#else
void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep)
{
    EXCEPTION_RECORD *rec = msvcrt_get_thread_data()->exc_record;

    TRACE("(%p)\n", ep);

    if (!rec)
    {
        ep->rec = NULL;
        ep->ref = NULL;
        return;
    }

    ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD));
    ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int));

    *ep->rec = *rec;
    *ep->ref = 1;

    if (ep->rec->ExceptionCode == CXX_EXCEPTION)
    {
        const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2];
        const cxx_type_info *ti;
        void **data, *obj;
        char *base = RtlPcToFileHeader((void*)et, (void**)&base);

        ti = (const cxx_type_info*)(base + ((const cxx_type_info_table*)(base + et->type_info_table))->info[0]);
        data = HeapAlloc(GetProcessHeap(), 0, ti->size);

        obj = (void*)ep->rec->ExceptionInformation[1];
        if (ti->flags & CLASS_IS_SIMPLE_TYPE)
        {
            memcpy(data, obj, ti->size);
            if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data);
        }
        else if (ti->copy_ctor)
        {
            call_copy_ctor(base + ti->copy_ctor, data, get_this_pointer(&ti->offsets, obj),
                    ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS);
        }
        else
            memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size);
        ep->rec->ExceptionInformation[1] = (ULONG_PTR)data;
    }
    return;
}
#endif
1479 1480 1481 1482 1483

void* __cdecl __AdjustPointer(void *obj, const this_ptr_offsets *off)
{
    return get_this_pointer(off, obj);
}