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