• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
my_alloc2(size_t sz)17 void *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 
my_dealloc2(void * p)23 void my_dealloc2 ( void *p ) {
24 //  std::printf ( "Freeing %lx\n", (unsigned long) p );
25     std::free ( p );
26     }
27 
my_dealloc3(void * p,size_t)28 void my_dealloc3 ( void *p, size_t ) {
29 //  std::printf ( "Freeing %lx (size %ld)\n", (unsigned long) p, sz );
30     std::free ( p );
31     }
32 
my_construct(void *)33 void my_construct ( void * ) {
34 //  std::printf ( "Constructing %lx\n", (unsigned long) p );
35     }
36 
my_destruct(void *)37 void my_destruct  ( void * ) {
38 //  std::printf ( "Destructing  %lx\n", (unsigned long) p );
39     }
40 
41 int gCounter;
count_construct(void *)42 void count_construct ( void * ) { ++gCounter; }
count_destruct(void *)43 void count_destruct  ( void * ) { --gCounter; }
44 
45 
46 int gConstructorCounter;
47 int gConstructorThrowTarget;
48 int gDestructorCounter;
49 int gDestructorThrowTarget;
throw_construct(void *)50 void throw_construct ( void * ) {
51 #ifndef LIBCXXABI_HAS_NO_EXCEPTIONS
52     if ( gConstructorCounter   == gConstructorThrowTarget )
53         throw 1;
54     ++gConstructorCounter;
55 #endif
56 }
throw_destruct(void *)57 void 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 
70 struct vec_on_stack {
71     void *storage;
vec_on_stackvec_on_stack72     vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new    (            10, 40, 8, throw_construct, throw_destruct )) {}
~vec_on_stackvec_on_stack73     ~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage,       40, 8,                  throw_destruct );  }
74     };
75 
76 //  Test calls with empty constructors and destructors
test_empty()77 int 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
test_counted()120 int 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
test_exception_in_constructor()162 int 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
test_exception_in_destructor()221 int 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 
main()272 int 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