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