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
my_alloc2(size_t sz)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
my_dealloc2(void * p)23 void my_dealloc2 ( void *p ) {
24 // std::printf ( "Freeing %lx\n", (unsigned long) p );
25 std::free ( p );
26 }
27
my_dealloc3(void * p,size_t)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
my_construct(void *)33 void my_construct ( void * ) {
34 // std::printf ( "Constructing %lx\n", (unsigned long) p );
35 }
36
my_destruct(void *)37 void my_destruct ( void * ) {
38 // std::printf ( "Destructing %lx\n", (unsigned long) p );
39 }
40
41 int gCounter;
count_construct(void *)42 void count_construct ( void * ) { ++gCounter; }
count_destruct(void *)43 void count_destruct ( void * ) { --gCounter; }
44
45
46 int gConstructorCounter;
47 int gConstructorThrowTarget;
48 int gDestructorCounter;
49 int gDestructorThrowTarget;
throw_construct(void *)50 void throw_construct ( void * ) {
51 #ifndef LIBCXXABI_HAS_NO_EXCEPTIONS
52 if ( gConstructorCounter == gConstructorThrowTarget )
53 throw 1;
54 ++gConstructorCounter;
55 #endif
56 }
throw_destruct(void *)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;
vec_on_stackvec_on_stack72 vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct )) {}
~vec_on_stackvec_on_stack73 ~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage, 40, 8, throw_destruct ); }
74 };
75
76 // Test calls with empty constructors and destructors
test_empty()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
test_counted()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
test_exception_in_constructor()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
test_exception_in_destructor()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
main()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