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