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