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