1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
15 #include "test_macros.h"
18 void *my_alloc2 ( size_t sz
) {
19 void *p
= std::malloc ( sz
);
20 // std::printf ( "Allocated %ld bytes at %lx\n", sz, (unsigned long) p );
24 void my_dealloc2 ( void *p
) {
25 // std::printf ( "Freeing %lx\n", (unsigned long) p );
29 void my_dealloc3 ( void *p
, size_t ) {
30 // std::printf ( "Freeing %lx (size %ld)\n", (unsigned long) p, sz );
34 void my_construct ( void * ) {
35 // std::printf ( "Constructing %lx\n", (unsigned long) p );
38 void my_destruct ( void * ) {
39 // std::printf ( "Destructing %lx\n", (unsigned long) p );
43 void count_construct ( void * ) { ++gCounter
; }
44 void count_destruct ( void * ) { --gCounter
; }
47 int gConstructorCounter
;
48 int gConstructorThrowTarget
;
49 int gDestructorCounter
;
50 int gDestructorThrowTarget
;
51 void throw_construct ( void * ) {
52 #ifndef TEST_HAS_NO_EXCEPTIONS
53 if ( gConstructorCounter
== gConstructorThrowTarget
)
55 ++gConstructorCounter
;
58 void throw_destruct ( void * ) {
59 #ifndef TEST_HAS_NO_EXCEPTIONS
60 if ( ++gDestructorCounter
== gDestructorThrowTarget
)
65 #if __cplusplus >= 201103L
66 # define CAN_THROW noexcept(false)
73 vec_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
); }
77 // Test calls with empty constructors and destructors
79 void *one
, *two
, *three
;
81 // Try with no padding and no con/destructors
82 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 0, NULL
, NULL
);
83 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 0, NULL
, NULL
, my_alloc2
, my_dealloc2
);
84 three
= __cxxabiv1::__cxa_vec_new3( 10, 40, 0, NULL
, NULL
, my_alloc2
, my_dealloc3
);
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
);
90 // Try with no padding
91 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 0, my_construct
, my_destruct
);
92 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 0, my_construct
, my_destruct
, my_alloc2
, my_dealloc2
);
93 three
= __cxxabiv1::__cxa_vec_new3( 10, 40, 0, my_construct
, my_destruct
, my_alloc2
, my_dealloc3
);
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
);
99 // Padding and no con/destructors
100 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 8, NULL
, NULL
);
101 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 8, NULL
, NULL
, my_alloc2
, my_dealloc2
);
102 three
= __cxxabiv1::__cxa_vec_new3( 10, 40, 8, NULL
, NULL
, my_alloc2
, my_dealloc3
);
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
);
108 // Padding with con/destructors
109 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 8, my_construct
, my_destruct
);
110 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 8, my_construct
, my_destruct
, my_alloc2
, my_dealloc2
);
111 three
= __cxxabiv1::__cxa_vec_new3( 10, 40, 8, my_construct
, my_destruct
, my_alloc2
, my_dealloc3
);
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
);
120 // Make sure the constructors and destructors are matched
121 int test_counted ( ) {
123 void *one
, *two
, *three
;
125 // Try with no padding
127 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 0, count_construct
, count_destruct
);
128 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 0, count_construct
, count_destruct
, my_alloc2
, my_dealloc2
);
129 three
= __cxxabiv1::__cxa_vec_new3( 10, 40, 0, count_construct
, count_destruct
, my_alloc2
, my_dealloc3
);
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
);
135 // Since there was no padding, the # of elements in the array are not stored
136 // and the destructors are not called.
137 if ( gCounter
!= 30 ) {
138 std::printf("Mismatched Constructor/Destructor calls (1)\n");
139 std::printf(" Expected 30, got %d\n", gCounter
);
144 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 8, count_construct
, count_destruct
);
145 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 8, count_construct
, count_destruct
, my_alloc2
, my_dealloc2
);
146 three
= __cxxabiv1::__cxa_vec_new3( 10, 40, 8, count_construct
, count_destruct
, my_alloc2
, my_dealloc3
);
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
);
152 if ( gCounter
!= 0 ) {
153 std::printf("Mismatched Constructor/Destructor calls (2)\n");
154 std::printf(" Expected 0, got %d\n", gCounter
);
161 #ifndef TEST_HAS_NO_EXCEPTIONS
162 // Make sure the constructors and destructors are matched
163 int test_exception_in_constructor ( ) {
165 void *one
, *two
, *three
;
167 // Try with no padding
168 gConstructorCounter
= gDestructorCounter
= 0;
169 gConstructorThrowTarget
= 15;
170 gDestructorThrowTarget
= -1;
172 one
= two
= three
= NULL
;
173 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 0, throw_construct
, throw_destruct
);
174 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 0, throw_construct
, throw_destruct
, my_alloc2
, my_dealloc2
);
175 three
= __cxxabiv1::__cxa_vec_new3( 10, 40, 0, throw_construct
, throw_destruct
, my_alloc2
, my_dealloc3
);
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
);
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.
187 if ( gConstructorCounter
- gDestructorCounter
!= 10 ) {
188 std::printf("Mismatched Constructor/Destructor calls (1C)\n");
189 std::printf("%d constructors, but %d destructors\n", gConstructorCounter
, gDestructorCounter
);
193 gConstructorCounter
= gDestructorCounter
= 0;
194 gConstructorThrowTarget
= 15;
195 gDestructorThrowTarget
= -1;
197 one
= two
= three
= NULL
;
198 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct
, throw_destruct
);
199 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct
, throw_destruct
, my_alloc2
, my_dealloc2
);
200 three
= __cxxabiv1::__cxa_vec_new3( 10, 40, 8, throw_construct
, throw_destruct
, my_alloc2
, my_dealloc3
);
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
);
208 if ( gConstructorCounter
!= gDestructorCounter
) {
209 std::printf("Mismatched Constructor/Destructor calls (2C)\n");
210 std::printf("%d constructors, but %d destructors\n", gConstructorCounter
, gDestructorCounter
);
218 #ifndef TEST_HAS_NO_EXCEPTIONS
219 // Make sure the constructors and destructors are matched
220 int test_exception_in_destructor ( ) {
222 void *one
, *two
, *three
;
223 one
= two
= three
= NULL
;
225 // Throw from within a destructor
226 gConstructorCounter
= gDestructorCounter
= 0;
227 gConstructorThrowTarget
= -1;
228 gDestructorThrowTarget
= 15;
231 one
= __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct
, throw_destruct
);
232 two
= __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct
, throw_destruct
, my_alloc2
, my_dealloc2
);
237 __cxxabiv1::__cxa_vec_delete ( one
, 40, 8, throw_destruct
);
238 __cxxabiv1::__cxa_vec_delete2( two
, 40, 8, throw_destruct
, my_dealloc2
);
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.
246 if ( gConstructorCounter
!= 20 || gDestructorCounter
!= 20 ) {
247 std::printf("Unexpected Constructor/Destructor calls (1D)\n");
248 std::printf("Expected (20, 20), but got (%d, %d)\n", gConstructorCounter
, gDestructorCounter
);
252 // Try throwing from a destructor - should be fine.
253 gConstructorCounter
= gDestructorCounter
= 0;
254 gConstructorThrowTarget
= -1;
255 gDestructorThrowTarget
= 5;
256 try { vec_on_stack v
; }
259 if ( gConstructorCounter
!= gDestructorCounter
) {
260 std::printf("Mismatched Constructor/Destructor calls (2D)\n");
261 std::printf("%d constructors, but %d destructors\n", gConstructorCounter
, gDestructorCounter
);
269 int main(int, char**) {
271 retVal
+= test_empty ();
272 retVal
+= test_counted ();
273 #ifndef TEST_HAS_NO_EXCEPTIONS
274 retVal
+= test_exception_in_constructor ();
275 retVal
+= test_exception_in_destructor ();