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