Home | History | Annotate | Download | only in test
      1 //===---------------------------- test_vector.cpp -------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "cxxabi.h"
     11 
     12 #include <iostream>
     13 #include <cstdlib>
     14 
     15 //  Wrapper routines
     16 void *my_alloc2 ( size_t sz ) {
     17     void *p = std::malloc ( sz );
     18 //  std::printf ( "Allocated %ld bytes at %lx\n", sz, (unsigned long) p );
     19     return p;
     20     }
     21 
     22 void my_dealloc2 ( void *p ) {
     23 //  std::printf ( "Freeing %lx\n", (unsigned long) p );
     24     std::free ( p );
     25     }
     26 
     27 void my_dealloc3 ( void *p, size_t   sz   ) {
     28 //  std::printf ( "Freeing %lx (size %ld)\n", (unsigned long) p, sz );
     29     std::free ( p );
     30     }
     31 
     32 void my_construct ( void *p ) {
     33 //  std::printf ( "Constructing %lx\n", (unsigned long) p );
     34     }
     35 
     36 void my_destruct  ( void *p ) {
     37 //  std::printf ( "Destructing  %lx\n", (unsigned long) p );
     38     }
     39 
     40 int gCounter;
     41 void count_construct ( void *p ) { ++gCounter; }
     42 void count_destruct  ( void *p ) { --gCounter; }
     43 
     44 
     45 int gConstructorCounter;
     46 int gConstructorThrowTarget;
     47 int gDestructorCounter;
     48 int gDestructorThrowTarget;
     49 void throw_construct ( void *p ) { if ( gConstructorCounter   == gConstructorThrowTarget ) throw 1; ++gConstructorCounter; }
     50 void throw_destruct  ( void *p ) { if ( ++gDestructorCounter  == gDestructorThrowTarget  ) throw 2; }
     51 
     52 #if __cplusplus >= 201103L
     53 #   define CAN_THROW noexcept(false)
     54 #else
     55 #   define CAN_THROW
     56 #endif
     57 
     58 struct vec_on_stack {
     59     void *storage;
     60     vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new    (            10, 40, 8, throw_construct, throw_destruct )) {}
     61     ~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage,       40, 8,                  throw_destruct );  }
     62     };
     63 
     64 //  Test calls with empty constructors and destructors
     65 int test_empty ( ) {
     66     void *one, *two, *three;
     67 
     68 //  Try with no padding and no con/destructors
     69     one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, NULL, NULL );
     70     two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, NULL, NULL, my_alloc2, my_dealloc2 );
     71     three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, NULL, NULL, my_alloc2, my_dealloc3 );
     72 
     73     __cxxabiv1::__cxa_vec_delete ( one,       40, 0, NULL );
     74     __cxxabiv1::__cxa_vec_delete2( two,       40, 0, NULL, my_dealloc2 );
     75     __cxxabiv1::__cxa_vec_delete3( three,     40, 0, NULL, my_dealloc3 );
     76 
     77 //  Try with no padding
     78     one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, my_construct, my_destruct );
     79     two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, my_construct, my_destruct, my_alloc2, my_dealloc2 );
     80     three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, my_construct, my_destruct, my_alloc2, my_dealloc3 );
     81 
     82     __cxxabiv1::__cxa_vec_delete ( one,       40, 0, my_destruct );
     83     __cxxabiv1::__cxa_vec_delete2( two,       40, 0, my_destruct, my_dealloc2 );
     84     __cxxabiv1::__cxa_vec_delete3( three,     40, 0, my_destruct, my_dealloc3 );
     85 
     86 //  Padding and no con/destructors
     87     one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, NULL, NULL );
     88     two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, NULL, NULL, my_alloc2, my_dealloc2 );
     89     three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, NULL, NULL, my_alloc2, my_dealloc3 );
     90 
     91     __cxxabiv1::__cxa_vec_delete ( one,       40, 8, NULL );
     92     __cxxabiv1::__cxa_vec_delete2( two,       40, 8, NULL, my_dealloc2 );
     93     __cxxabiv1::__cxa_vec_delete3( three,     40, 8, NULL, my_dealloc3 );
     94 
     95 //  Padding with con/destructors
     96     one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, my_construct, my_destruct );
     97     two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, my_construct, my_destruct, my_alloc2, my_dealloc2 );
     98     three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, my_construct, my_destruct, my_alloc2, my_dealloc3 );
     99 
    100     __cxxabiv1::__cxa_vec_delete ( one,       40, 8, my_destruct );
    101     __cxxabiv1::__cxa_vec_delete2( two,       40, 8, my_destruct, my_dealloc2 );
    102     __cxxabiv1::__cxa_vec_delete3( three,     40, 8, my_destruct, my_dealloc3 );
    103 
    104     return 0;
    105     }
    106 
    107 //  Make sure the constructors and destructors are matched
    108 int test_counted ( ) {
    109     int retVal = 0;
    110     void *one, *two, *three;
    111 
    112 //  Try with no padding
    113     gCounter = 0;
    114     one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, count_construct, count_destruct );
    115     two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, count_construct, count_destruct, my_alloc2, my_dealloc2 );
    116     three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, count_construct, count_destruct, my_alloc2, my_dealloc3 );
    117 
    118     __cxxabiv1::__cxa_vec_delete ( one,       40, 0, count_destruct );
    119     __cxxabiv1::__cxa_vec_delete2( two,       40, 0, count_destruct, my_dealloc2 );
    120     __cxxabiv1::__cxa_vec_delete3( three,     40, 0, count_destruct, my_dealloc3 );
    121 
    122 //  Since there was no padding, the # of elements in the array are not stored
    123 //  and the destructors are not called.
    124     if ( gCounter != 30 ) {
    125         std::cerr << "Mismatched Constructor/Destructor calls (1)" << std::endl;
    126         std::cerr << "  Expected 30, got " << gCounter << std::endl;
    127         retVal = 1;
    128         }
    129 
    130     gCounter = 0;
    131     one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, count_construct, count_destruct );
    132     two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, count_construct, count_destruct, my_alloc2, my_dealloc2 );
    133     three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, count_construct, count_destruct, my_alloc2, my_dealloc3 );
    134 
    135     __cxxabiv1::__cxa_vec_delete ( one,       40, 8, count_destruct );
    136     __cxxabiv1::__cxa_vec_delete2( two,       40, 8, count_destruct, my_dealloc2 );
    137     __cxxabiv1::__cxa_vec_delete3( three,     40, 8, count_destruct, my_dealloc3 );
    138 
    139     if ( gCounter != 0 ) {
    140         std::cerr << "Mismatched Constructor/Destructor calls (2)" << std::endl;
    141         std::cerr << "  Expected 0, got " << gCounter << std::endl;
    142         retVal = 1;
    143         }
    144 
    145     return retVal;
    146     }
    147 
    148 //  Make sure the constructors and destructors are matched
    149 int test_exception_in_constructor ( ) {
    150     int retVal = 0;
    151     void *one, *two, *three;
    152 
    153 //  Try with no padding
    154     gConstructorCounter = gDestructorCounter = 0;
    155     gConstructorThrowTarget = 15;
    156     gDestructorThrowTarget  = -1;
    157     try {
    158         one = two = three = NULL;
    159         one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, throw_construct, throw_destruct );
    160         two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
    161         three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
    162         }
    163     catch ( int i ) {}
    164 
    165     __cxxabiv1::__cxa_vec_delete ( one,       40, 0, throw_destruct );
    166     __cxxabiv1::__cxa_vec_delete2( two,       40, 0, throw_destruct, my_dealloc2 );
    167     __cxxabiv1::__cxa_vec_delete3( three,     40, 0, throw_destruct, my_dealloc3 );
    168 
    169 //  Since there was no padding, the # of elements in the array are not stored
    170 //  and the destructors are not called.
    171 //  Since we threw after 15 calls to the constructor, we should see 5 calls to
    172 //      the destructor from the partially constructed array.
    173     if ( gConstructorCounter - gDestructorCounter != 10 ) {
    174         std::cerr << "Mismatched Constructor/Destructor calls (1C)" << std::endl;
    175         std::cerr << gConstructorCounter << " constructors, but " <<
    176                 gDestructorCounter << " destructors" << std::endl;
    177         retVal = 1;
    178         }
    179 
    180     gConstructorCounter = gDestructorCounter = 0;
    181     gConstructorThrowTarget = 15;
    182     gDestructorThrowTarget  = -1;
    183     try {
    184         one = two = three = NULL;
    185         one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct );
    186         two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
    187         three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
    188         }
    189     catch ( int i ) {}
    190 
    191     __cxxabiv1::__cxa_vec_delete ( one,       40, 8, throw_destruct );
    192     __cxxabiv1::__cxa_vec_delete2( two,       40, 8, throw_destruct, my_dealloc2 );
    193     __cxxabiv1::__cxa_vec_delete3( three,     40, 8, throw_destruct, my_dealloc3 );
    194 
    195     if ( gConstructorCounter != gDestructorCounter ) {
    196         std::cerr << "Mismatched Constructor/Destructor calls (2C)" << std::endl;
    197         std::cerr << gConstructorCounter << " constructors, but " <<
    198                 gDestructorCounter << " destructors" << std::endl;
    199         retVal = 1;
    200         }
    201 
    202     return retVal;
    203     }
    204 
    205 //  Make sure the constructors and destructors are matched
    206 int test_exception_in_destructor ( ) {
    207     int retVal = 0;
    208     void *one, *two, *three;
    209 
    210 //  Throw from within a destructor
    211     gConstructorCounter = gDestructorCounter = 0;
    212     gConstructorThrowTarget = -1;
    213     gDestructorThrowTarget  = 15;
    214     try {
    215         one = two = three = NULL;
    216         one     = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct );
    217         two     = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
    218         three   = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
    219         }
    220     catch ( int i ) {}
    221 
    222     try {
    223         __cxxabiv1::__cxa_vec_delete ( one,       40, 8, throw_destruct );
    224         __cxxabiv1::__cxa_vec_delete2( two,       40, 8, throw_destruct, my_dealloc2 );
    225         __cxxabiv1::__cxa_vec_delete3( three,     40, 8, throw_destruct, my_dealloc3 );
    226         }
    227     catch ( int i ) {}
    228 
    229 //  We should have thrown in the middle of cleaning up "two", which means that
    230 //  there should be 20 calls to the destructor, and "three" was not cleaned up.
    231     if ( gConstructorCounter != 30 || gDestructorCounter != 20 ) {
    232         std::cerr << "Unexpected Constructor/Destructor calls (1D)" << std::endl;
    233         std::cerr << "Expected (30, 20), but got (" << gConstructorCounter << ", " <<
    234                 gDestructorCounter << ")" << std::endl;
    235         retVal = 1;
    236         }
    237 
    238 //  Try throwing from a destructor - should be fine.
    239     gConstructorCounter = gDestructorCounter = 0;
    240     gConstructorThrowTarget = -1;
    241     gDestructorThrowTarget  = 5;
    242     try { vec_on_stack v; }
    243     catch ( int i ) {}
    244 
    245     if ( gConstructorCounter != gDestructorCounter ) {
    246         std::cerr << "Mismatched Constructor/Destructor calls (2D)" << std::endl;
    247         std::cerr << gConstructorCounter << " constructors, but " <<
    248                 gDestructorCounter << " destructors" << std::endl;
    249         retVal = 1;
    250         }
    251 
    252     return retVal;
    253     }
    254 
    255 int main ( int argc, char *argv [] ) {
    256     int retVal = 0;
    257     retVal += test_empty ();
    258     retVal += test_counted ();
    259     retVal += test_exception_in_constructor ();
    260     retVal += test_exception_in_destructor ();
    261     return retVal;
    262     }
    263