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