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
15 // Wrapper routines
my_alloc2(size_t sz)16 void *my_alloc2 ( size_t sz ) {
17 void *p = std::malloc ( sz );
18 // std::printf ( "Allocated %ld bytes at %lx\n", sz, (unsigned long) p );
19 return p;
20 }
21
my_dealloc2(void * p)22 void my_dealloc2 ( void *p ) {
23 // std::printf ( "Freeing %lx\n", (unsigned long) p );
24 std::free ( p );
25 }
26
my_dealloc3(void * p,size_t sz)27 void my_dealloc3 ( void *p, size_t sz ) {
28 // std::printf ( "Freeing %lx (size %ld)\n", (unsigned long) p, sz );
29 std::free ( p );
30 }
31
my_construct(void * p)32 void my_construct ( void *p ) {
33 // std::printf ( "Constructing %lx\n", (unsigned long) p );
34 }
35
my_destruct(void * p)36 void my_destruct ( void *p ) {
37 // std::printf ( "Destructing %lx\n", (unsigned long) p );
38 }
39
40 int gCounter;
count_construct(void * p)41 void count_construct ( void *p ) { ++gCounter; }
count_destruct(void * p)42 void count_destruct ( void *p ) { --gCounter; }
43
44
45 int gConstructorCounter;
46 int gConstructorThrowTarget;
47 int gDestructorCounter;
48 int gDestructorThrowTarget;
throw_construct(void * p)49 void throw_construct ( void *p ) { if ( gConstructorCounter == gConstructorThrowTarget ) throw 1; ++gConstructorCounter; }
throw_destruct(void * p)50 void throw_destruct ( void *p ) { if ( ++gDestructorCounter == gDestructorThrowTarget ) throw 2; }
51
52 #if __cplusplus >= 201103L
53 # define CAN_THROW noexcept(false)
54 #else
55 # define CAN_THROW
56 #endif
57
58 struct vec_on_stack {
59 void *storage;
vec_on_stackvec_on_stack60 vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct )) {}
~vec_on_stackvec_on_stack61 ~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage, 40, 8, throw_destruct ); }
62 };
63
64 // Test calls with empty constructors and destructors
test_empty()65 int test_empty ( ) {
66 void *one, *two, *three;
67
68 // Try with no padding and no con/destructors
69 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, NULL, NULL );
70 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, NULL, NULL, my_alloc2, my_dealloc2 );
71 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, NULL, NULL, my_alloc2, my_dealloc3 );
72
73 __cxxabiv1::__cxa_vec_delete ( one, 40, 0, NULL );
74 __cxxabiv1::__cxa_vec_delete2( two, 40, 0, NULL, my_dealloc2 );
75 __cxxabiv1::__cxa_vec_delete3( three, 40, 0, NULL, my_dealloc3 );
76
77 // Try with no padding
78 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, my_construct, my_destruct );
79 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, my_construct, my_destruct, my_alloc2, my_dealloc2 );
80 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, my_construct, my_destruct, my_alloc2, my_dealloc3 );
81
82 __cxxabiv1::__cxa_vec_delete ( one, 40, 0, my_destruct );
83 __cxxabiv1::__cxa_vec_delete2( two, 40, 0, my_destruct, my_dealloc2 );
84 __cxxabiv1::__cxa_vec_delete3( three, 40, 0, my_destruct, my_dealloc3 );
85
86 // Padding and no con/destructors
87 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, NULL, NULL );
88 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, NULL, NULL, my_alloc2, my_dealloc2 );
89 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, NULL, NULL, my_alloc2, my_dealloc3 );
90
91 __cxxabiv1::__cxa_vec_delete ( one, 40, 8, NULL );
92 __cxxabiv1::__cxa_vec_delete2( two, 40, 8, NULL, my_dealloc2 );
93 __cxxabiv1::__cxa_vec_delete3( three, 40, 8, NULL, my_dealloc3 );
94
95 // Padding with con/destructors
96 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, my_construct, my_destruct );
97 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, my_construct, my_destruct, my_alloc2, my_dealloc2 );
98 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, my_construct, my_destruct, my_alloc2, my_dealloc3 );
99
100 __cxxabiv1::__cxa_vec_delete ( one, 40, 8, my_destruct );
101 __cxxabiv1::__cxa_vec_delete2( two, 40, 8, my_destruct, my_dealloc2 );
102 __cxxabiv1::__cxa_vec_delete3( three, 40, 8, my_destruct, my_dealloc3 );
103
104 return 0;
105 }
106
107 // Make sure the constructors and destructors are matched
test_counted()108 int test_counted ( ) {
109 int retVal = 0;
110 void *one, *two, *three;
111
112 // Try with no padding
113 gCounter = 0;
114 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, count_construct, count_destruct );
115 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, count_construct, count_destruct, my_alloc2, my_dealloc2 );
116 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, count_construct, count_destruct, my_alloc2, my_dealloc3 );
117
118 __cxxabiv1::__cxa_vec_delete ( one, 40, 0, count_destruct );
119 __cxxabiv1::__cxa_vec_delete2( two, 40, 0, count_destruct, my_dealloc2 );
120 __cxxabiv1::__cxa_vec_delete3( three, 40, 0, count_destruct, my_dealloc3 );
121
122 // Since there was no padding, the # of elements in the array are not stored
123 // and the destructors are not called.
124 if ( gCounter != 30 ) {
125 std::cerr << "Mismatched Constructor/Destructor calls (1)" << std::endl;
126 std::cerr << " Expected 30, got " << gCounter << std::endl;
127 retVal = 1;
128 }
129
130 gCounter = 0;
131 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, count_construct, count_destruct );
132 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, count_construct, count_destruct, my_alloc2, my_dealloc2 );
133 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, count_construct, count_destruct, my_alloc2, my_dealloc3 );
134
135 __cxxabiv1::__cxa_vec_delete ( one, 40, 8, count_destruct );
136 __cxxabiv1::__cxa_vec_delete2( two, 40, 8, count_destruct, my_dealloc2 );
137 __cxxabiv1::__cxa_vec_delete3( three, 40, 8, count_destruct, my_dealloc3 );
138
139 if ( gCounter != 0 ) {
140 std::cerr << "Mismatched Constructor/Destructor calls (2)" << std::endl;
141 std::cerr << " Expected 0, got " << gCounter << std::endl;
142 retVal = 1;
143 }
144
145 return retVal;
146 }
147
148 // Make sure the constructors and destructors are matched
test_exception_in_constructor()149 int test_exception_in_constructor ( ) {
150 int retVal = 0;
151 void *one, *two, *three;
152
153 // Try with no padding
154 gConstructorCounter = gDestructorCounter = 0;
155 gConstructorThrowTarget = 15;
156 gDestructorThrowTarget = -1;
157 try {
158 one = two = three = NULL;
159 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, throw_construct, throw_destruct );
160 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
161 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
162 }
163 catch ( int i ) {}
164
165 __cxxabiv1::__cxa_vec_delete ( one, 40, 0, throw_destruct );
166 __cxxabiv1::__cxa_vec_delete2( two, 40, 0, throw_destruct, my_dealloc2 );
167 __cxxabiv1::__cxa_vec_delete3( three, 40, 0, throw_destruct, my_dealloc3 );
168
169 // Since there was no padding, the # of elements in the array are not stored
170 // and the destructors are not called.
171 // Since we threw after 15 calls to the constructor, we should see 5 calls to
172 // the destructor from the partially constructed array.
173 if ( gConstructorCounter - gDestructorCounter != 10 ) {
174 std::cerr << "Mismatched Constructor/Destructor calls (1C)" << std::endl;
175 std::cerr << gConstructorCounter << " constructors, but " <<
176 gDestructorCounter << " destructors" << std::endl;
177 retVal = 1;
178 }
179
180 gConstructorCounter = gDestructorCounter = 0;
181 gConstructorThrowTarget = 15;
182 gDestructorThrowTarget = -1;
183 try {
184 one = two = three = NULL;
185 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct );
186 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
187 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
188 }
189 catch ( int i ) {}
190
191 __cxxabiv1::__cxa_vec_delete ( one, 40, 8, throw_destruct );
192 __cxxabiv1::__cxa_vec_delete2( two, 40, 8, throw_destruct, my_dealloc2 );
193 __cxxabiv1::__cxa_vec_delete3( three, 40, 8, throw_destruct, my_dealloc3 );
194
195 if ( gConstructorCounter != gDestructorCounter ) {
196 std::cerr << "Mismatched Constructor/Destructor calls (2C)" << std::endl;
197 std::cerr << gConstructorCounter << " constructors, but " <<
198 gDestructorCounter << " destructors" << std::endl;
199 retVal = 1;
200 }
201
202 return retVal;
203 }
204
205 // Make sure the constructors and destructors are matched
test_exception_in_destructor()206 int test_exception_in_destructor ( ) {
207 int retVal = 0;
208 void *one, *two, *three;
209
210 // Throw from within a destructor
211 gConstructorCounter = gDestructorCounter = 0;
212 gConstructorThrowTarget = -1;
213 gDestructorThrowTarget = 15;
214 try {
215 one = two = three = NULL;
216 one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct );
217 two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
218 three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
219 }
220 catch ( int i ) {}
221
222 try {
223 __cxxabiv1::__cxa_vec_delete ( one, 40, 8, throw_destruct );
224 __cxxabiv1::__cxa_vec_delete2( two, 40, 8, throw_destruct, my_dealloc2 );
225 __cxxabiv1::__cxa_vec_delete3( three, 40, 8, throw_destruct, my_dealloc3 );
226 }
227 catch ( int i ) {}
228
229 // We should have thrown in the middle of cleaning up "two", which means that
230 // there should be 20 calls to the destructor, and "three" was not cleaned up.
231 if ( gConstructorCounter != 30 || gDestructorCounter != 20 ) {
232 std::cerr << "Unexpected Constructor/Destructor calls (1D)" << std::endl;
233 std::cerr << "Expected (30, 20), but got (" << gConstructorCounter << ", " <<
234 gDestructorCounter << ")" << std::endl;
235 retVal = 1;
236 }
237
238 // Try throwing from a destructor - should be fine.
239 gConstructorCounter = gDestructorCounter = 0;
240 gConstructorThrowTarget = -1;
241 gDestructorThrowTarget = 5;
242 try { vec_on_stack v; }
243 catch ( int i ) {}
244
245 if ( gConstructorCounter != gDestructorCounter ) {
246 std::cerr << "Mismatched Constructor/Destructor calls (2D)" << std::endl;
247 std::cerr << gConstructorCounter << " constructors, but " <<
248 gDestructorCounter << " destructors" << std::endl;
249 retVal = 1;
250 }
251
252 return retVal;
253 }
254
main(int argc,char * argv[])255 int main ( int argc, char *argv [] ) {
256 int retVal = 0;
257 retVal += test_empty ();
258 retVal += test_counted ();
259 retVal += test_exception_in_constructor ();
260 retVal += test_exception_in_destructor ();
261 return retVal;
262 }
263