blob: 6790cb5aa7db5f6f70659ca16770bd3d6e973471 [file] [log] [blame]
Marshall Clow280ddee2011-06-10 03:40:19 +00001//===---------------------------- 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>
Eric Fiseliera3158652014-11-21 01:53:51 +000014#include <cassert>
Marshall Clow280ddee2011-06-10 03:40:19 +000015
16// Wrapper routines
17void *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
23void my_dealloc2 ( void *p ) {
24// std::printf ( "Freeing %lx\n", (unsigned long) p );
25 std::free ( p );
26 }
27
28void 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
33void my_construct ( void *p ) {
34// std::printf ( "Constructing %lx\n", (unsigned long) p );
35 }
36
37void my_destruct ( void *p ) {
38// std::printf ( "Destructing %lx\n", (unsigned long) p );
39 }
40
41int gCounter;
42void count_construct ( void *p ) { ++gCounter; }
43void count_destruct ( void *p ) { --gCounter; }
44
45
46int gConstructorCounter;
47int gConstructorThrowTarget;
48int gDestructorCounter;
49int gDestructorThrowTarget;
50void throw_construct ( void *p ) { if ( gConstructorCounter == gConstructorThrowTarget ) throw 1; ++gConstructorCounter; }
51void throw_destruct ( void *p ) { if ( ++gDestructorCounter == gDestructorThrowTarget ) throw 2; }
52
Logan Chiencc24fc52014-05-10 00:40:54 +000053#if __cplusplus >= 201103L
Howard Hinnant3d979312012-01-31 20:10:33 +000054# define CAN_THROW noexcept(false)
55#else
56# define CAN_THROW
57#endif
58
Marshall Clow280ddee2011-06-10 03:40:19 +000059struct vec_on_stack {
60 void *storage;
61 vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct )) {}
Howard Hinnant3d979312012-01-31 20:10:33 +000062 ~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage, 40, 8, throw_destruct ); }
Marshall Clow280ddee2011-06-10 03:40:19 +000063 };
64
65// Test calls with empty constructors and destructors
66int 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
109int 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
150int 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
Marshall Clow92091db2011-06-13 17:57:10 +0000206// Make sure the constructors and destructors are matched
207int test_exception_in_destructor ( ) {
208 int retVal = 0;
209 void *one, *two, *three;
Eric Fiseliera3158652014-11-21 01:53:51 +0000210 one = two = three = NULL;
Marshall Clow92091db2011-06-13 17:57:10 +0000211
212// Throw from within a destructor
213 gConstructorCounter = gDestructorCounter = 0;
214 gConstructorThrowTarget = -1;
215 gDestructorThrowTarget = 15;
216 try {
Eric Fiseliera3158652014-11-21 01:53:51 +0000217 one = two = NULL;
Marshall Clow92091db2011-06-13 17:57:10 +0000218 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 );
Marshall Clow92091db2011-06-13 17:57:10 +0000220 }
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 );
Eric Fiseliera3158652014-11-21 01:53:51 +0000226 assert(false);
Marshall Clow92091db2011-06-13 17:57:10 +0000227 }
228 catch ( int i ) {}
229
230// We should have thrown in the middle of cleaning up "two", which means that
Eric Fiseliera3158652014-11-21 01:53:51 +0000231// there should be 20 calls to the destructor and the try block should exit
232// before the assertion.
233 if ( gConstructorCounter != 20 || gDestructorCounter != 20 ) {
Marshall Clow92091db2011-06-13 17:57:10 +0000234 std::cerr << "Unexpected Constructor/Destructor calls (1D)" << std::endl;
Eric Fiseliera3158652014-11-21 01:53:51 +0000235 std::cerr << "Expected (20, 20), but got (" << gConstructorCounter << ", " <<
Marshall Clow92091db2011-06-13 17:57:10 +0000236 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 }
Marshall Clow280ddee2011-06-10 03:40:19 +0000256
257int main ( int argc, char *argv [] ) {
258 int retVal = 0;
259 retVal += test_empty ();
260 retVal += test_counted ();
261 retVal += test_exception_in_constructor ();
Marshall Clow92091db2011-06-13 17:57:10 +0000262 retVal += test_exception_in_destructor ();
Marshall Clow280ddee2011-06-10 03:40:19 +0000263 return retVal;
264 }