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