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