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 sz)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
my_construct(void * p)33 void my_construct ( void *p ) {
34 // std::printf ( "Constructing %lx\n", (unsigned long) p );
35 }
36
my_destruct(void * p)37 void my_destruct ( void *p ) {
38 // std::printf ( "Destructing %lx\n", (unsigned long) p );
39 }
40
41 int gCounter;
count_construct(void * p)42 void count_construct ( void *p ) { ++gCounter; }
count_destruct(void * p)43 void count_destruct ( void *p ) { --gCounter; }
44
45
46 int gConstructorCounter;
47 int gConstructorThrowTarget;
48 int gDestructorCounter;
49 int gDestructorThrowTarget;
throw_construct(void * p)50 void throw_construct ( void *p ) { if ( gConstructorCounter == gConstructorThrowTarget ) throw 1; ++gConstructorCounter; }
throw_destruct(void * p)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;
vec_on_stackvec_on_stack61 vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct )) {}
~vec_on_stackvec_on_stack62 ~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage, 40, 8, throw_destruct ); }
63 };
64
65 // Test calls with empty constructors and destructors
test_empty()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
test_counted()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
test_exception_in_constructor()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
test_exception_in_destructor()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
main(int argc,char * argv[])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