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