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
33 using std::size_t;
34
35 namespace {
36
37 using namespace __cxxabiv1;
38
39 typedef __cxa_vec_constructor constructor_func;
40 typedef __cxa_vec_copy_constructor copy_constructor_func;
41 typedef __cxa_vec_destructor destructor_func;
42 typedef void* (*alloc_func)(size_t);
43 typedef void (*dealloc_func)(void*);
44 typedef 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.
48 class scoped_block {
49 public:
scoped_block(void * ptr,size_t size,dealloc2_func dealloc)50 scoped_block(void* ptr, size_t size, dealloc2_func dealloc)
51 : ptr_(ptr), size_(size), dealloc_(dealloc) {}
52
~scoped_block()53 ~scoped_block() {
54 if (dealloc_)
55 dealloc_(ptr_, size_);
56 }
57
release()58 void release() {
59 dealloc_ = 0;
60 }
61
62 private:
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.
70 class scoped_cleanup {
71 public:
scoped_cleanup(void * array,size_t & index,size_t element_size,destructor_func destructor)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
~scoped_cleanup()77 ~scoped_cleanup() {
78 if (destructor_)
79 __cxxabiv1::__cxa_vec_cleanup(array_,
80 index_,
81 element_size_,
82 destructor_);
83 }
84
release()85 void release() {
86 destructor_ = 0;
87 }
88 private:
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().
97 class scoped_catcher {
98 public:
scoped_catcher(const char * message)99 scoped_catcher(const char* message) : message_(message) {}
100
~scoped_catcher()101 ~scoped_catcher() {
102 if (message_)
103 __gabixx::__fatal_error(message_);
104 }
105
release()106 void release() {
107 message_ = 0;
108 }
109
110 private:
111 const char* message_;
112 };
113
114 } // namespace
115
116 namespace __cxxabiv1 {
117 extern "C" {
118
__cxa_vec_new(size_t element_count,size_t element_size,size_t padding_size,constructor_func constructor,destructor_func destructor)119 void* __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
__cxa_vec_new2(size_t element_count,size_t element_size,size_t padding_size,constructor_func constructor,destructor_func destructor,alloc_func alloc,dealloc_func dealloc)129 void* __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
__cxa_vec_new3(size_t element_count,size_t element_size,size_t padding_size,constructor_func constructor,destructor_func destructor,alloc_func alloc,dealloc2_func dealloc)145 void* __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
__cxa_vec_ctor(void * array_address,size_t element_count,size_t element_size,constructor_func constructor,destructor_func destructor)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.
__cxa_vec_dtor(void * array_address,size_t element_count,size_t element_size,destructor_func destructor)225 void __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.
__cxa_vec_cleanup(void * array_address,size_t element_count,size_t element_size,destructor_func destructor)250 void __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.
__cxa_vec_delete(void * array_address,size_t element_size,size_t padding_size,destructor_func destructor)280 void __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.
__cxa_vec_delete2(void * array_address,size_t element_size,size_t padding_size,destructor_func destructor,dealloc_func dealloc)292 void __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.
__cxa_vec_delete3(void * array_address,size_t element_size,size_t padding_size,destructor_func destructor,dealloc2_func dealloc)308 void __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
__cxa_vec_cctor(void * dst_array,void * src_array,size_t element_count,size_t element_size,copy_constructor_func copy_constructor,destructor_func destructor)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.
370 namespace __aeabiv1 {
371
372 extern "C" {
373
374 using namespace __cxxabiv1;
375
__aeabi_vec_ctor_nocookie_nodtor(void * array_address,constructor_func constructor,size_t element_size,size_t element_count)376 void* __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
__aeabi_vec_ctor_cookie_nodtor(void * array_address,constructor_func constructor,size_t element_size,size_t element_count)387 void* __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
__aeabi_vec_cctor_nocookie_nodtor(void * dst_array,void * src_array,size_t element_size,size_t element_count,copy_constructor_func copy_constructor)404 void* __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
__aeabi_vec_new_cookie_noctor(size_t element_size,size_t element_count)414 void* __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
__aeabi_vec_new_nocookie(size_t element_size,size_t element_count,constructor_func constructor)422 void* __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
__aeabi_vec_new_cookie_nodtor(size_t element_size,size_t element_count,constructor_func constructor)432 void* __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
__aeabi_vec_new_cookie(size_t element_size,size_t element_count,constructor_func constructor,destructor_func destructor)442 void* __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
__aeabi_vec_dtor(void * array_address,destructor_func destructor,size_t element_size,size_t element_count)453 void* __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
__aeabi_vec_dtor_cookie(void * array_address,destructor_func destructor)462 void* __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
__aeabi_vec_delete(void * array_address,destructor_func destructor)475 void __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
__aeabi_vec_delete3(void * array_address,destructor_func destructor,dealloc2_func dealloc)487 void __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
__aeabi_vec_delete3_nodtor(void * array_address,dealloc2_func dealloc)501 void __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