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