1// Copyright (C) 2013 The Android Open Source Project
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1. Redistributions of source code must retain the above copyright
8//    notice, this list of conditions and the following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright
10//    notice, this list of conditions and the following disclaimer in the
11//    documentation and/or other materials provided with the distribution.
12// 3. Neither the name of the project nor the names of its contributors
13//    may be used to endorse or promote products derived from this software
14//    without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19// ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26// SUCH DAMAGE.
27
28#include <cstddef>
29#include <new>
30
31#include "cxxabi_defines.h"
32
33using std::size_t;
34
35namespace {
36
37using namespace __cxxabiv1;
38
39typedef __cxa_vec_constructor constructor_func;
40typedef __cxa_vec_copy_constructor copy_constructor_func;
41typedef __cxa_vec_destructor destructor_func;
42typedef void* (*alloc_func)(size_t);
43typedef void (*dealloc_func)(void*);
44typedef void (*dealloc2_func)(void*, size_t);
45
46// Helper class to ensure a ptr is deallocated on scope exit unless
47// the release() method has been called.
48class scoped_block {
49public:
50  scoped_block(void* ptr, size_t size, dealloc2_func dealloc)
51    : ptr_(ptr), size_(size), dealloc_(dealloc) {}
52
53  ~scoped_block() {
54    if (dealloc_)
55      dealloc_(ptr_, size_);
56  }
57
58  void release() {
59    dealloc_ = 0;
60  }
61
62private:
63  void* ptr_;
64  size_t size_;
65  dealloc2_func dealloc_;
66};
67
68// Helper class to ensure a vector is cleaned up on scope exit
69// unless the release() method has been called.
70class scoped_cleanup {
71public:
72  scoped_cleanup(void* array, size_t& index, size_t element_size,
73                destructor_func destructor)
74    : array_(array), index_(index), element_size_(element_size),
75      destructor_(destructor) {}
76
77  ~scoped_cleanup() {
78    if (destructor_)
79      __cxxabiv1::__cxa_vec_cleanup(array_,
80                                    index_,
81                                    element_size_,
82                                    destructor_);
83  }
84
85  void release() {
86    destructor_ = 0;
87  }
88private:
89  void* array_;
90  size_t& index_;
91  size_t element_size_;
92  destructor_func destructor_;
93};
94
95// Helper class that calls __fatal_error() with a given message if
96// it exits a scope without a previous call to release().
97class scoped_catcher {
98public:
99  scoped_catcher(const char* message) : message_(message) {}
100
101  ~scoped_catcher() {
102    if (message_)
103      __gabixx::__fatal_error(message_);
104  }
105
106  void release() {
107    message_ = 0;
108  }
109
110private:
111  const char* message_;
112};
113
114}  // namespace
115
116namespace __cxxabiv1 {
117extern "C" {
118
119void* __cxa_vec_new(size_t element_count,
120                    size_t element_size,
121                    size_t padding_size,
122                    constructor_func constructor,
123                    destructor_func destructor) {
124  return __cxa_vec_new2(element_count, element_size, padding_size,
125                        constructor, destructor,
126                        &operator new[], &operator delete []);
127}
128
129void* __cxa_vec_new2(size_t element_count,
130                     size_t element_size,
131                     size_t padding_size,
132                     constructor_func constructor,
133                     destructor_func destructor,
134                     alloc_func alloc,
135                     dealloc_func dealloc) {
136  // The only difference with __cxa_vec_new3 is the type of the
137  // dealloc parameter. force a cast because on all supported
138  // platforms, it is possible to call the dealloc function here
139  // with two parameters. The second one will simply be ignored.
140  return __cxa_vec_new3(element_count, element_size, padding_size,
141                        constructor, destructor, alloc,
142                        reinterpret_cast<dealloc2_func>(dealloc));
143}
144
145void* __cxa_vec_new3(size_t element_count,
146                     size_t element_size,
147                     size_t padding_size,
148                     constructor_func constructor,
149                     destructor_func destructor,
150                     alloc_func alloc,
151                     dealloc2_func dealloc) {
152  // Compute the size of the needed memory block, and throw
153  // std::bad_alloc() on overflow.
154  bool overflow = false;
155  size_t size = 0;
156  if (element_size > 0 && element_count > size_t(-1) / element_size)
157    overflow = true;
158  else {
159    size = element_count * element_size;
160    if (size + padding_size < size)
161      overflow = true;
162  }
163  if (overflow)
164    throw std::bad_alloc();
165
166  // Allocate memory. Do not throw if NULL is returned.
167  char* base = static_cast<char*>(alloc(size));
168  if (!base)
169    return base;
170
171  // Ensure the block is freed if construction throws.
172  scoped_block block(base, size, dealloc);
173
174  if (padding_size) {
175    base += padding_size;
176    reinterpret_cast<size_t*>(base)[-1] = element_count;
177#ifdef __arm__
178    // Required by the ARM C++ ABI.
179    reinterpret_cast<size_t*>(base)[-2] = element_size;
180#endif
181  }
182
183  __cxa_vec_ctor(base, element_count, element_size,
184                 constructor, destructor);
185
186  // Construction succeeded, no need to release the block.
187  block.release();
188  return base;
189}
190
191#ifdef __arm__
192// On ARM, __cxa_vec_ctor and __cxa_vec_cctor must return
193// their first parameter. Handle this here.
194#define _CXA_VEC_CTOR_RETURN(x) return x
195#else
196#define _CXA_VEC_CTOR_RETURN(x) return
197#endif
198
199__cxa_vec_ctor_return_type
200__cxa_vec_ctor(void* array_address,
201               size_t element_count,
202               size_t element_size,
203               constructor_func constructor,
204               destructor_func destructor) {
205  if (constructor) {
206    size_t n = 0;
207    char* base = static_cast<char*>(array_address);
208
209    scoped_cleanup cleanup(array_address, n, element_size, destructor);
210    for (; n != element_count; ++n) {
211      constructor(base);
212      base += element_size;
213    }
214    cleanup.release();
215  }
216  _CXA_VEC_CTOR_RETURN(array_address);
217}
218
219// Given the (data) address of an array, the number of elements,
220// and the size of its elements, call the given destructor on each
221// element. If the destructor throws an exception, rethrow after
222// destroying the remaining elements if possible. If the destructor
223// throws a second exception, call terminate(). The destructor
224// pointer may be NULL, in which case this routine does nothing.
225void __cxa_vec_dtor(void* array_address,
226                    size_t element_count,
227                    size_t element_size,
228                    destructor_func destructor) {
229  if (!destructor)
230    return;
231
232  char* base = static_cast<char*>(array_address);
233  size_t n = element_count;
234  scoped_cleanup cleanup(array_address, n, element_size, destructor);
235  base += element_count * element_size;
236  // Note: n must be decremented before the destructor call
237  // to avoid cleaning up one extra unwanted item.
238  while (n--) {
239    base -= element_size;
240    destructor(base);
241  }
242  cleanup.release();
243}
244
245// Given the (data) address of an array, the number of elements,
246// and the size of its elements, call the given destructor on each
247// element. If the destructor throws an exception, call terminate().
248// The destructor pointer may be NULL, in which case this routine
249// does nothing.
250void __cxa_vec_cleanup(void* array_address,
251                       size_t element_count,
252                       size_t element_size,
253                       destructor_func destructor) {
254  if (!destructor)
255    return;
256
257  char* base = static_cast<char*>(array_address);
258  size_t n = element_count;
259  base += n * element_size;
260
261  scoped_catcher catcher("exception raised in vector destructor!");
262  while (n--) {
263    base -= element_size;
264    destructor(base);
265  }
266  catcher.release();
267}
268
269// If the array_address is NULL, return immediately. Otherwise,
270// given the (data) address of an array, the non-negative size
271// of prefix padding for the cookie, and the size of its elements,
272// call the given destructor on each element, using the cookie to
273// determine the number of elements, and then delete the space by
274// calling ::operator delete[](void *). If the destructor throws an
275// exception, rethrow after (a) destroying the remaining elements,
276// and (b) deallocating the storage. If the destructor throws a
277// second exception, call terminate(). If padding_size is 0, the
278// destructor pointer must be NULL. If the destructor pointer is NULL,
279// no destructor call is to be made.
280void __cxa_vec_delete(void* array_address,
281                      size_t element_size,
282                      size_t padding_size,
283                      destructor_func destructor) {
284  __cxa_vec_delete2(array_address, element_size, padding_size,
285                    destructor, &operator delete []);
286}
287
288// Same as __cxa_vec_delete, except that the given function is used
289// for deallocation instead of the default delete function. If dealloc
290// throws an exception, the result is undefined. The dealloc pointer
291// may not be NULL.
292void __cxa_vec_delete2(void* array_address,
293                       size_t element_size,
294                       size_t padding_size,
295                       destructor_func destructor,
296                       dealloc_func dealloc) {
297  // Same trick than the one used on __cxa_vec_new2.
298  __cxa_vec_delete3(array_address, element_size, padding_size,
299                    destructor,
300                    reinterpret_cast<dealloc2_func>(dealloc));
301}
302
303// Same as __cxa_vec_delete, except that the given function is used
304// for deallocation instead of the default delete function. The
305// deallocation function takes both the object address and its size.
306// If dealloc throws an exception, the result is undefined. The dealloc
307// pointer may not be NULL.
308void __cxa_vec_delete3(void* array_address,
309                       size_t element_size,
310                       size_t padding_size,
311                       destructor_func destructor,
312                       dealloc2_func dealloc) {
313  if (!array_address)
314    return;
315
316  char* base = static_cast<char*>(array_address);
317
318  if (!padding_size) {
319    // If here is no padding size, asume the deallocator knows
320    // how to handle this. Useful when called from __cxa_vec_delete2.
321    dealloc(base, 0);
322    return;
323  }
324
325  size_t element_count = reinterpret_cast<size_t*>(base)[-1];
326  base -= padding_size;
327  size_t size = element_count * element_size + padding_size;
328
329  // Always deallocate base on exit.
330  scoped_block block(base, size, dealloc);
331
332  if (padding_size > 0 && destructor != 0)
333    __cxa_vec_dtor(array_address, element_count, element_size, destructor);
334}
335
336__cxa_vec_ctor_return_type
337__cxa_vec_cctor(void* dst_array,
338                void* src_array,
339                size_t element_count,
340                size_t element_size,
341                copy_constructor_func copy_constructor,
342                destructor_func destructor) {
343  if (copy_constructor) {
344    size_t n = 0;
345    char* dst = static_cast<char*>(dst_array);
346    char* src = static_cast<char*>(src_array);
347
348    scoped_cleanup cleanup(dst_array, n, element_size, destructor);
349
350    for ( ; n != element_count; ++n) {
351      copy_constructor(dst, src);
352      dst += element_size;
353      src += element_size;
354    }
355
356    cleanup.release();
357  }
358  _CXA_VEC_CTOR_RETURN(dst_array);
359}
360
361}  // extern "C"
362}  // namespace __cxxabiv1
363
364#if _GABIXX_ARM_ABI
365// The following functions are required by the ARM ABI, even
366// though neither GCC nor LLVM generate any code that uses it.
367// This may be important for machine code generated by other
368// compilers though (e.g. RCVT), which may depend on them.
369// They're supposed to simplify calling code.
370namespace __aeabiv1 {
371
372extern "C" {
373
374using namespace __cxxabiv1;
375
376void* __aeabi_vec_ctor_nocookie_nodtor(void* array_address,
377                                       constructor_func constructor,
378                                       size_t element_size,
379                                       size_t element_count) {
380  return __cxa_vec_ctor(array_address,
381                        element_count,
382                        element_size,
383                        constructor,
384                        /* destructor */ NULL);
385}
386
387void* __aeabi_vec_ctor_cookie_nodtor(void* array_address,
388                                     constructor_func constructor,
389                                     size_t element_size,
390                                     size_t element_count) {
391  if (!array_address)
392    return array_address;
393
394  size_t* base = reinterpret_cast<size_t*>(array_address) + 2;
395  base[-2] = element_size;
396  base[-1] = element_count;
397  return __cxa_vec_ctor(base,
398                        element_count,
399                        element_size,
400                        constructor,
401                        /* destructor */ NULL);
402}
403
404void* __aeabi_vec_cctor_nocookie_nodtor(
405    void* dst_array,
406    void* src_array,
407    size_t element_size,
408    size_t element_count,
409    copy_constructor_func copy_constructor) {
410  return __cxa_vec_cctor(dst_array, src_array, element_count,
411                         element_size, copy_constructor, NULL);
412}
413
414void* __aeabi_vec_new_cookie_noctor(size_t element_size,
415                                    size_t element_count) {
416  return __cxa_vec_new(element_count, element_size,
417                       /* padding */ 2 * sizeof(size_t),
418                       /* constructor */ NULL,
419                       /* destructor */ NULL);
420}
421
422void* __aeabi_vec_new_nocookie(size_t element_size,
423                               size_t element_count,
424                               constructor_func constructor) {
425  return __cxa_vec_new(element_count,
426                       element_size,
427                       /* padding */ 0,
428                       constructor,
429                       /* destructor */ NULL);
430}
431
432void* __aeabi_vec_new_cookie_nodtor(size_t element_size,
433                                    size_t element_count,
434                                    constructor_func constructor) {
435  return __cxa_vec_new(element_count,
436                       element_size,
437                       /* padding */ 2 * sizeof(size_t),
438                       constructor,
439                       /* destructor */ NULL);
440}
441
442void* __aeabi_vec_new_cookie(size_t element_size,
443                             size_t element_count,
444                             constructor_func constructor,
445                             destructor_func destructor) {
446  return __cxa_vec_new(element_count,
447                       element_size,
448                       /* padding */ 2 * sizeof(size_t),
449                       constructor,
450                       destructor);
451}
452
453void* __aeabi_vec_dtor(void* array_address,
454                       destructor_func destructor,
455                       size_t element_size,
456                       size_t element_count) {
457  __cxa_vec_dtor(array_address, element_count, element_size,
458                 destructor);
459    return reinterpret_cast<size_t*>(array_address) - 2;
460}
461
462void* __aeabi_vec_dtor_cookie(void* array_address,
463                              destructor_func destructor) {
464  if (!array_address)
465    return NULL;
466
467  size_t* base = reinterpret_cast<size_t*>(array_address);
468  __cxa_vec_dtor(array_address,
469                 /* element_count */ base[-1],
470                 /* element_size */ base[-2],
471                 destructor);
472  return base - 2;
473}
474
475void __aeabi_vec_delete(void* array_address,
476                        destructor_func destructor)  {
477  if (array_address) {
478    size_t* base = reinterpret_cast<size_t*>(array_address);
479
480    __cxa_vec_delete(array_address,
481                    /* element_size */ base[-2],
482                    /* padding */ 2 * sizeof(size_t),
483                    destructor);
484  }
485}
486
487void __aeabi_vec_delete3(void* array_address,
488                         destructor_func destructor,
489                         dealloc2_func dealloc) {
490  if (array_address) {
491    size_t* base = reinterpret_cast<size_t*>(array_address);
492
493    __cxa_vec_delete3(array_address,
494                     /* element_size */ base[-2],
495                     /* padding */ 2 * sizeof(size_t),
496                     destructor,
497                     dealloc);
498  }
499}
500
501void __aeabi_vec_delete3_nodtor(void* array_address,
502                                dealloc2_func dealloc) {
503  if (array_address) {
504    size_t* base = reinterpret_cast<size_t*>(array_address);
505
506    __cxa_vec_delete3(array_address,
507                     /* element_size */ base[-2],
508                     /* padding */ 2 * sizeof(size_t),
509                     /* destructor */ NULL,
510                     dealloc);
511  }
512}
513
514}  // extern "C"
515}  // namespace __aeabiv1
516
517#endif  // _GABIXX_ARM_ABI
518