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