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