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