1*eb8650a7SLouis Dionne //===----------------------------------------------------------------------===//
2e434b34fSJonathan Roelofs //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e434b34fSJonathan Roelofs //
7e434b34fSJonathan Roelofs //===----------------------------------------------------------------------===//
8e434b34fSJonathan Roelofs
9e434b34fSJonathan Roelofs #include "cxxabi.h"
10e434b34fSJonathan Roelofs
11e434b34fSJonathan Roelofs #include <cassert>
12cc69d211SLouis Dionne #include <cstdio>
13cc69d211SLouis Dionne #include <cstdlib>
14e434b34fSJonathan Roelofs
15e6d94f4bSLouis Dionne #include "test_macros.h"
16e6d94f4bSLouis Dionne
17e434b34fSJonathan Roelofs // Wrapper routines
my_alloc2(size_t sz)18e434b34fSJonathan Roelofs void *my_alloc2 ( size_t sz ) {
19e434b34fSJonathan Roelofs void *p = std::malloc ( sz );
20e434b34fSJonathan Roelofs // std::printf ( "Allocated %ld bytes at %lx\n", sz, (unsigned long) p );
21e434b34fSJonathan Roelofs return p;
22e434b34fSJonathan Roelofs }
23e434b34fSJonathan Roelofs
my_dealloc2(void * p)24e434b34fSJonathan Roelofs void my_dealloc2 ( void *p ) {
25e434b34fSJonathan Roelofs // std::printf ( "Freeing %lx\n", (unsigned long) p );
26e434b34fSJonathan Roelofs std::free ( p );
27e434b34fSJonathan Roelofs }
28e434b34fSJonathan Roelofs
my_dealloc3(void * p,size_t)29a140cba7SEric Fiselier void my_dealloc3 ( void *p, size_t ) {
30e434b34fSJonathan Roelofs // std::printf ( "Freeing %lx (size %ld)\n", (unsigned long) p, sz );
31e434b34fSJonathan Roelofs std::free ( p );
32e434b34fSJonathan Roelofs }
33e434b34fSJonathan Roelofs
my_construct(void *)34a140cba7SEric Fiselier void my_construct ( void * ) {
35e434b34fSJonathan Roelofs // std::printf ( "Constructing %lx\n", (unsigned long) p );
36e434b34fSJonathan Roelofs }
37e434b34fSJonathan Roelofs
my_destruct(void *)38a140cba7SEric Fiselier void my_destruct ( void * ) {
39e434b34fSJonathan Roelofs // std::printf ( "Destructing %lx\n", (unsigned long) p );
40e434b34fSJonathan Roelofs }
41e434b34fSJonathan Roelofs
42e434b34fSJonathan Roelofs int gCounter;
count_construct(void *)43a140cba7SEric Fiselier void count_construct ( void * ) { ++gCounter; }
count_destruct(void *)44a140cba7SEric Fiselier void count_destruct ( void * ) { --gCounter; }
45e434b34fSJonathan Roelofs
46e434b34fSJonathan Roelofs
47e434b34fSJonathan Roelofs int gConstructorCounter;
48e434b34fSJonathan Roelofs int gConstructorThrowTarget;
49e434b34fSJonathan Roelofs int gDestructorCounter;
50e434b34fSJonathan Roelofs int gDestructorThrowTarget;
throw_construct(void *)51a140cba7SEric Fiselier void throw_construct ( void * ) {
52e6d94f4bSLouis Dionne #ifndef TEST_HAS_NO_EXCEPTIONS
5357e446daSAsiri Rathnayake if ( gConstructorCounter == gConstructorThrowTarget )
5457e446daSAsiri Rathnayake throw 1;
5557e446daSAsiri Rathnayake ++gConstructorCounter;
5657e446daSAsiri Rathnayake #endif
5757e446daSAsiri Rathnayake }
throw_destruct(void *)58a140cba7SEric Fiselier void throw_destruct ( void * ) {
59e6d94f4bSLouis Dionne #ifndef TEST_HAS_NO_EXCEPTIONS
6057e446daSAsiri Rathnayake if ( ++gDestructorCounter == gDestructorThrowTarget )
6157e446daSAsiri Rathnayake throw 2;
6257e446daSAsiri Rathnayake #endif
6357e446daSAsiri Rathnayake }
64e434b34fSJonathan Roelofs
65e434b34fSJonathan Roelofs #if __cplusplus >= 201103L
66e434b34fSJonathan Roelofs # define CAN_THROW noexcept(false)
67e434b34fSJonathan Roelofs #else
68e434b34fSJonathan Roelofs # define CAN_THROW
69e434b34fSJonathan Roelofs #endif
70e434b34fSJonathan Roelofs
71e434b34fSJonathan Roelofs struct vec_on_stack {
72e434b34fSJonathan Roelofs void *storage;
vec_on_stackvec_on_stack73e434b34fSJonathan Roelofs vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct )) {}
~vec_on_stackvec_on_stack74e434b34fSJonathan Roelofs ~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage, 40, 8, throw_destruct ); }
75e434b34fSJonathan Roelofs };
76e434b34fSJonathan Roelofs
77e434b34fSJonathan Roelofs // Test calls with empty constructors and destructors
test_empty()78e434b34fSJonathan Roelofs int test_empty ( ) {
79e434b34fSJonathan Roelofs void *one, *two, *three;
80e434b34fSJonathan Roelofs
81e434b34fSJonathan Roelofs // Try with no padding and no con/destructors
82e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, NULL, NULL );
83e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, NULL, NULL, my_alloc2, my_dealloc2 );
84e434b34fSJonathan Roelofs three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, NULL, NULL, my_alloc2, my_dealloc3 );
85e434b34fSJonathan Roelofs
86e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 0, NULL );
87e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 0, NULL, my_dealloc2 );
88e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete3( three, 40, 0, NULL, my_dealloc3 );
89e434b34fSJonathan Roelofs
90e434b34fSJonathan Roelofs // Try with no padding
91e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, my_construct, my_destruct );
92e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, my_construct, my_destruct, my_alloc2, my_dealloc2 );
93e434b34fSJonathan Roelofs three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, my_construct, my_destruct, my_alloc2, my_dealloc3 );
94e434b34fSJonathan Roelofs
95e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 0, my_destruct );
96e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 0, my_destruct, my_dealloc2 );
97e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete3( three, 40, 0, my_destruct, my_dealloc3 );
98e434b34fSJonathan Roelofs
99e434b34fSJonathan Roelofs // Padding and no con/destructors
100e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, NULL, NULL );
101e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, NULL, NULL, my_alloc2, my_dealloc2 );
102e434b34fSJonathan Roelofs three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, NULL, NULL, my_alloc2, my_dealloc3 );
103e434b34fSJonathan Roelofs
104e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 8, NULL );
105e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 8, NULL, my_dealloc2 );
106e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete3( three, 40, 8, NULL, my_dealloc3 );
107e434b34fSJonathan Roelofs
108e434b34fSJonathan Roelofs // Padding with con/destructors
109e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, my_construct, my_destruct );
110e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, my_construct, my_destruct, my_alloc2, my_dealloc2 );
111e434b34fSJonathan Roelofs three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, my_construct, my_destruct, my_alloc2, my_dealloc3 );
112e434b34fSJonathan Roelofs
113e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 8, my_destruct );
114e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 8, my_destruct, my_dealloc2 );
115e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete3( three, 40, 8, my_destruct, my_dealloc3 );
116e434b34fSJonathan Roelofs
117e434b34fSJonathan Roelofs return 0;
118e434b34fSJonathan Roelofs }
119e434b34fSJonathan Roelofs
120e434b34fSJonathan Roelofs // Make sure the constructors and destructors are matched
test_counted()121e434b34fSJonathan Roelofs int test_counted ( ) {
122e434b34fSJonathan Roelofs int retVal = 0;
123e434b34fSJonathan Roelofs void *one, *two, *three;
124e434b34fSJonathan Roelofs
125e434b34fSJonathan Roelofs // Try with no padding
126e434b34fSJonathan Roelofs gCounter = 0;
127e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, count_construct, count_destruct );
128e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, count_construct, count_destruct, my_alloc2, my_dealloc2 );
129e434b34fSJonathan Roelofs three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, count_construct, count_destruct, my_alloc2, my_dealloc3 );
130e434b34fSJonathan Roelofs
131e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 0, count_destruct );
132e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 0, count_destruct, my_dealloc2 );
133e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete3( three, 40, 0, count_destruct, my_dealloc3 );
134e434b34fSJonathan Roelofs
135e434b34fSJonathan Roelofs // Since there was no padding, the # of elements in the array are not stored
136e434b34fSJonathan Roelofs // and the destructors are not called.
137e434b34fSJonathan Roelofs if ( gCounter != 30 ) {
138cc69d211SLouis Dionne std::printf("Mismatched Constructor/Destructor calls (1)\n");
139cc69d211SLouis Dionne std::printf(" Expected 30, got %d\n", gCounter);
140e434b34fSJonathan Roelofs retVal = 1;
141e434b34fSJonathan Roelofs }
142e434b34fSJonathan Roelofs
143e434b34fSJonathan Roelofs gCounter = 0;
144e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, count_construct, count_destruct );
145e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, count_construct, count_destruct, my_alloc2, my_dealloc2 );
146e434b34fSJonathan Roelofs three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, count_construct, count_destruct, my_alloc2, my_dealloc3 );
147e434b34fSJonathan Roelofs
148e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 8, count_destruct );
149e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 8, count_destruct, my_dealloc2 );
150e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete3( three, 40, 8, count_destruct, my_dealloc3 );
151e434b34fSJonathan Roelofs
152e434b34fSJonathan Roelofs if ( gCounter != 0 ) {
153cc69d211SLouis Dionne std::printf("Mismatched Constructor/Destructor calls (2)\n");
154cc69d211SLouis Dionne std::printf(" Expected 0, got %d\n", gCounter);
155e434b34fSJonathan Roelofs retVal = 1;
156e434b34fSJonathan Roelofs }
157e434b34fSJonathan Roelofs
158e434b34fSJonathan Roelofs return retVal;
159e434b34fSJonathan Roelofs }
160e434b34fSJonathan Roelofs
161e6d94f4bSLouis Dionne #ifndef TEST_HAS_NO_EXCEPTIONS
162e434b34fSJonathan Roelofs // Make sure the constructors and destructors are matched
test_exception_in_constructor()163e434b34fSJonathan Roelofs int test_exception_in_constructor ( ) {
164e434b34fSJonathan Roelofs int retVal = 0;
165e434b34fSJonathan Roelofs void *one, *two, *three;
166e434b34fSJonathan Roelofs
167e434b34fSJonathan Roelofs // Try with no padding
168e434b34fSJonathan Roelofs gConstructorCounter = gDestructorCounter = 0;
169e434b34fSJonathan Roelofs gConstructorThrowTarget = 15;
170e434b34fSJonathan Roelofs gDestructorThrowTarget = -1;
171e434b34fSJonathan Roelofs try {
172e434b34fSJonathan Roelofs one = two = three = NULL;
173e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, throw_construct, throw_destruct );
174e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
175e434b34fSJonathan Roelofs three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
176e434b34fSJonathan Roelofs }
177e434b34fSJonathan Roelofs catch ( int i ) {}
178e434b34fSJonathan Roelofs
179e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 0, throw_destruct );
180e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 0, throw_destruct, my_dealloc2 );
181e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete3( three, 40, 0, throw_destruct, my_dealloc3 );
182e434b34fSJonathan Roelofs
183e434b34fSJonathan Roelofs // Since there was no padding, the # of elements in the array are not stored
184e434b34fSJonathan Roelofs // and the destructors are not called.
185e434b34fSJonathan Roelofs // Since we threw after 15 calls to the constructor, we should see 5 calls to
186e434b34fSJonathan Roelofs // the destructor from the partially constructed array.
187e434b34fSJonathan Roelofs if ( gConstructorCounter - gDestructorCounter != 10 ) {
188cc69d211SLouis Dionne std::printf("Mismatched Constructor/Destructor calls (1C)\n");
189cc69d211SLouis Dionne std::printf("%d constructors, but %d destructors\n", gConstructorCounter, gDestructorCounter);
190e434b34fSJonathan Roelofs retVal = 1;
191e434b34fSJonathan Roelofs }
192e434b34fSJonathan Roelofs
193e434b34fSJonathan Roelofs gConstructorCounter = gDestructorCounter = 0;
194e434b34fSJonathan Roelofs gConstructorThrowTarget = 15;
195e434b34fSJonathan Roelofs gDestructorThrowTarget = -1;
196e434b34fSJonathan Roelofs try {
197e434b34fSJonathan Roelofs one = two = three = NULL;
198e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct );
199e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
200e434b34fSJonathan Roelofs three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
201e434b34fSJonathan Roelofs }
202e434b34fSJonathan Roelofs catch ( int i ) {}
203e434b34fSJonathan Roelofs
204e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 8, throw_destruct );
205e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 8, throw_destruct, my_dealloc2 );
206e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete3( three, 40, 8, throw_destruct, my_dealloc3 );
207e434b34fSJonathan Roelofs
208e434b34fSJonathan Roelofs if ( gConstructorCounter != gDestructorCounter ) {
209cc69d211SLouis Dionne std::printf("Mismatched Constructor/Destructor calls (2C)\n");
210cc69d211SLouis Dionne std::printf("%d constructors, but %d destructors\n", gConstructorCounter, gDestructorCounter);
211e434b34fSJonathan Roelofs retVal = 1;
212e434b34fSJonathan Roelofs }
213e434b34fSJonathan Roelofs
214e434b34fSJonathan Roelofs return retVal;
215e434b34fSJonathan Roelofs }
21657e446daSAsiri Rathnayake #endif
217e434b34fSJonathan Roelofs
218e6d94f4bSLouis Dionne #ifndef TEST_HAS_NO_EXCEPTIONS
219e434b34fSJonathan Roelofs // Make sure the constructors and destructors are matched
test_exception_in_destructor()220e434b34fSJonathan Roelofs int test_exception_in_destructor ( ) {
221e434b34fSJonathan Roelofs int retVal = 0;
222e434b34fSJonathan Roelofs void *one, *two, *three;
223e434b34fSJonathan Roelofs one = two = three = NULL;
224e434b34fSJonathan Roelofs
225e434b34fSJonathan Roelofs // Throw from within a destructor
226e434b34fSJonathan Roelofs gConstructorCounter = gDestructorCounter = 0;
227e434b34fSJonathan Roelofs gConstructorThrowTarget = -1;
228e434b34fSJonathan Roelofs gDestructorThrowTarget = 15;
229e434b34fSJonathan Roelofs try {
230e434b34fSJonathan Roelofs one = two = NULL;
231e434b34fSJonathan Roelofs one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct );
232e434b34fSJonathan Roelofs two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
233e434b34fSJonathan Roelofs }
234e434b34fSJonathan Roelofs catch ( int i ) {}
235e434b34fSJonathan Roelofs
236e434b34fSJonathan Roelofs try {
237e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete ( one, 40, 8, throw_destruct );
238e434b34fSJonathan Roelofs __cxxabiv1::__cxa_vec_delete2( two, 40, 8, throw_destruct, my_dealloc2 );
239e434b34fSJonathan Roelofs assert(false);
240e434b34fSJonathan Roelofs }
241e434b34fSJonathan Roelofs catch ( int i ) {}
242e434b34fSJonathan Roelofs
243e434b34fSJonathan Roelofs // We should have thrown in the middle of cleaning up "two", which means that
244e434b34fSJonathan Roelofs // there should be 20 calls to the destructor and the try block should exit
245e434b34fSJonathan Roelofs // before the assertion.
246e434b34fSJonathan Roelofs if ( gConstructorCounter != 20 || gDestructorCounter != 20 ) {
247cc69d211SLouis Dionne std::printf("Unexpected Constructor/Destructor calls (1D)\n");
248cc69d211SLouis Dionne std::printf("Expected (20, 20), but got (%d, %d)\n", gConstructorCounter, gDestructorCounter);
249e434b34fSJonathan Roelofs retVal = 1;
250e434b34fSJonathan Roelofs }
251e434b34fSJonathan Roelofs
252e434b34fSJonathan Roelofs // Try throwing from a destructor - should be fine.
253e434b34fSJonathan Roelofs gConstructorCounter = gDestructorCounter = 0;
254e434b34fSJonathan Roelofs gConstructorThrowTarget = -1;
255e434b34fSJonathan Roelofs gDestructorThrowTarget = 5;
256e434b34fSJonathan Roelofs try { vec_on_stack v; }
257e434b34fSJonathan Roelofs catch ( int i ) {}
258e434b34fSJonathan Roelofs
259e434b34fSJonathan Roelofs if ( gConstructorCounter != gDestructorCounter ) {
260cc69d211SLouis Dionne std::printf("Mismatched Constructor/Destructor calls (2D)\n");
261cc69d211SLouis Dionne std::printf("%d constructors, but %d destructors\n", gConstructorCounter, gDestructorCounter);
262e434b34fSJonathan Roelofs retVal = 1;
263e434b34fSJonathan Roelofs }
264e434b34fSJonathan Roelofs
265e434b34fSJonathan Roelofs return retVal;
266e434b34fSJonathan Roelofs }
26757e446daSAsiri Rathnayake #endif
268e434b34fSJonathan Roelofs
main(int,char **)269cc69d211SLouis Dionne int main(int, char**) {
270e434b34fSJonathan Roelofs int retVal = 0;
271e434b34fSJonathan Roelofs retVal += test_empty ();
272e434b34fSJonathan Roelofs retVal += test_counted ();
273e6d94f4bSLouis Dionne #ifndef TEST_HAS_NO_EXCEPTIONS
274e434b34fSJonathan Roelofs retVal += test_exception_in_constructor ();
275e434b34fSJonathan Roelofs retVal += test_exception_in_destructor ();
27657e446daSAsiri Rathnayake #endif
277e434b34fSJonathan Roelofs return retVal;
278e434b34fSJonathan Roelofs }
279