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
my_alloc2(size_t sz)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
my_dealloc2(void * p)22 void my_dealloc2 ( void *p ) {
23 // printf ( "Freeing %p\n", p );
24 std::free ( p );
25 }
26
my_dealloc3(void * p,size_t sz)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
my_construct(void * p)40 CTOR_RETURN_TYPE my_construct ( void *p ) {
41 // printf ( "Constructing %p\n", p );
42 CTOR_RETURN(p);
43 }
44
my_destruct(void * p)45 CTOR_RETURN_TYPE my_destruct ( void *p ) {
46 // printf ( "Destructing %p\n", p );
47 CTOR_RETURN(p);
48 }
49
50 int gCounter;
count_construct(void * p)51 CTOR_RETURN_TYPE count_construct ( void *p ) { ++gCounter; CTOR_RETURN(p); }
count_destruct(void * 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;
throw_construct(void * p)59 CTOR_RETURN_TYPE throw_construct ( void *p ) {
60 if ( gConstructorCounter == gConstructorThrowTarget )
61 throw 1;
62 ++gConstructorCounter;
63 CTOR_RETURN(p);
64 }
65
throw_destruct(void * p)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;
vec_on_stackvec_on_stack80 vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct )) {}
~vec_on_stackvec_on_stack81 ~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage, 40, 8, throw_destruct ); }
82 };
83
84 // Test calls with empty constructors and destructors
test_empty()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
test_counted()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
test_exception_in_constructor()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
test_exception_in_destructor()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
main(int argc,char * argv[])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