1 | //===-------------------------- cxa_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 | // This file implements the "Array Construction and Destruction APIs" |
9 | // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-ctor |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "cxxabi.h" |
14 | #include "__cxxabi_config.h" |
15 | |
16 | #include <exception> // for std::terminate |
17 | #include <new> // for std::bad_array_new_length |
18 | |
19 | #include "abort_message.h" |
20 | |
21 | #ifndef __has_builtin |
22 | #define __has_builtin(x) 0 |
23 | #endif |
24 | |
25 | namespace __cxxabiv1 { |
26 | |
27 | #if 0 |
28 | #pragma mark --Helper routines and classes -- |
29 | #endif |
30 | |
31 | namespace { |
32 | inline static size_t __get_element_count ( void *p ) { |
33 | return static_cast <size_t *> (p)[-1]; |
34 | } |
35 | |
36 | inline static void __set_element_count ( void *p, size_t element_count ) { |
37 | static_cast <size_t *> (p)[-1] = element_count; |
38 | } |
39 | |
40 | |
41 | // A pair of classes to simplify exception handling and control flow. |
42 | // They get passed a block of memory in the constructor, and unless the |
43 | // 'release' method is called, they deallocate the memory in the destructor. |
44 | // Preferred usage is to allocate some memory, attach it to one of these objects, |
45 | // and then, when all the operations to set up the memory block have succeeded, |
46 | // call 'release'. If any of the setup operations fail, or an exception is |
47 | // thrown, then the block is automatically deallocated. |
48 | // |
49 | // The only difference between these two classes is the signature for the |
50 | // deallocation function (to match new2/new3 and delete2/delete3. |
51 | class st_heap_block2 { |
52 | public: |
53 | typedef void (*dealloc_f)(void *); |
54 | |
55 | st_heap_block2 ( dealloc_f dealloc, void *ptr ) |
56 | : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {} |
57 | ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; } |
58 | void release () { enabled_ = false; } |
59 | |
60 | private: |
61 | dealloc_f dealloc_; |
62 | void *ptr_; |
63 | bool enabled_; |
64 | }; |
65 | |
66 | class st_heap_block3 { |
67 | public: |
68 | typedef void (*dealloc_f)(void *, size_t); |
69 | |
70 | st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size ) |
71 | : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {} |
72 | ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; } |
73 | void release () { enabled_ = false; } |
74 | |
75 | private: |
76 | dealloc_f dealloc_; |
77 | void *ptr_; |
78 | size_t size_; |
79 | bool enabled_; |
80 | }; |
81 | |
82 | class st_cxa_cleanup { |
83 | public: |
84 | typedef void (*destruct_f)(void *); |
85 | |
86 | st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor ) |
87 | : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ), |
88 | destructor_ ( destructor ), enabled_ ( true ) {} |
89 | ~st_cxa_cleanup () { |
90 | if ( enabled_ ) |
91 | __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ ); |
92 | } |
93 | |
94 | void release () { enabled_ = false; } |
95 | |
96 | private: |
97 | void *ptr_; |
98 | size_t &idx_; |
99 | size_t element_size_; |
100 | destruct_f destructor_; |
101 | bool enabled_; |
102 | }; |
103 | |
104 | class st_terminate { |
105 | public: |
106 | st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {} |
107 | ~st_terminate () { if ( enabled_ ) std::terminate (); } |
108 | void release () { enabled_ = false; } |
109 | private: |
110 | bool enabled_ ; |
111 | }; |
112 | } |
113 | |
114 | #if 0 |
115 | #pragma mark --Externally visible routines-- |
116 | #endif |
117 | |
118 | namespace { |
119 | _LIBCXXABI_NORETURN |
120 | void throw_bad_array_new_length() { |
121 | #ifndef _LIBCXXABI_NO_EXCEPTIONS |
122 | throw std::bad_array_new_length(); |
123 | #else |
124 | abort_message("__cxa_vec_new failed to allocate memory" ); |
125 | #endif |
126 | } |
127 | |
128 | bool mul_overflow(size_t x, size_t y, size_t *res) { |
129 | #if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_mul_overflow)) \ |
130 | || defined(_LIBCXXABI_COMPILER_GCC) |
131 | return __builtin_mul_overflow(x, y, res); |
132 | #else |
133 | *res = x * y; |
134 | return x && ((*res / x) != y); |
135 | #endif |
136 | } |
137 | |
138 | bool add_overflow(size_t x, size_t y, size_t *res) { |
139 | #if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_add_overflow)) \ |
140 | || defined(_LIBCXXABI_COMPILER_GCC) |
141 | return __builtin_add_overflow(x, y, res); |
142 | #else |
143 | *res = x + y; |
144 | return *res < y; |
145 | #endif |
146 | } |
147 | |
148 | size_t calculate_allocation_size_or_throw(size_t element_count, |
149 | size_t element_size, |
150 | size_t padding_size) { |
151 | size_t element_heap_size; |
152 | if (mul_overflow(element_count, element_size, &element_heap_size)) |
153 | throw_bad_array_new_length(); |
154 | |
155 | size_t allocation_size; |
156 | if (add_overflow(element_heap_size, padding_size, &allocation_size)) |
157 | throw_bad_array_new_length(); |
158 | |
159 | return allocation_size; |
160 | } |
161 | |
162 | } // namespace |
163 | |
164 | extern "C" { |
165 | |
166 | // Equivalent to |
167 | // |
168 | // __cxa_vec_new2(element_count, element_size, padding_size, constructor, |
169 | // destructor, &::operator new[], &::operator delete[]) |
170 | _LIBCXXABI_FUNC_VIS void * |
171 | __cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size, |
172 | void (*constructor)(void *), void (*destructor)(void *)) { |
173 | return __cxa_vec_new2 ( element_count, element_size, padding_size, |
174 | constructor, destructor, &::operator new [], &::operator delete [] ); |
175 | } |
176 | |
177 | |
178 | // Given the number and size of elements for an array and the non-negative |
179 | // size of prefix padding for a cookie, allocate space (using alloc) for |
180 | // the array preceded by the specified padding, initialize the cookie if |
181 | // the padding is non-zero, and call the given constructor on each element. |
182 | // Return the address of the array proper, after the padding. |
183 | // |
184 | // If alloc throws an exception, rethrow the exception. If alloc returns |
185 | // NULL, return NULL. If the constructor throws an exception, call |
186 | // destructor for any already constructed elements, and rethrow the |
187 | // exception. If the destructor throws an exception, call std::terminate. |
188 | // |
189 | // The constructor may be NULL, in which case it must not be called. If the |
190 | // padding_size is zero, the destructor may be NULL; in that case it must |
191 | // not be called. |
192 | // |
193 | // Neither alloc nor dealloc may be NULL. |
194 | _LIBCXXABI_FUNC_VIS void * |
195 | __cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size, |
196 | void (*constructor)(void *), void (*destructor)(void *), |
197 | void *(*alloc)(size_t), void (*dealloc)(void *)) { |
198 | const size_t heap_size = calculate_allocation_size_or_throw( |
199 | element_count, element_size, padding_size); |
200 | char* const heap_block = static_cast<char*>(alloc(heap_size)); |
201 | char* vec_base = heap_block; |
202 | |
203 | if (NULL != vec_base) { |
204 | st_heap_block2 heap(dealloc, heap_block); |
205 | |
206 | // put the padding before the array elements |
207 | if ( 0 != padding_size ) { |
208 | vec_base += padding_size; |
209 | __set_element_count ( vec_base, element_count ); |
210 | } |
211 | |
212 | // Construct the elements |
213 | __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor ); |
214 | heap.release (); // We're good! |
215 | } |
216 | |
217 | return vec_base; |
218 | } |
219 | |
220 | |
221 | // Same as __cxa_vec_new2 except that the deallocation function takes both |
222 | // the object address and its size. |
223 | _LIBCXXABI_FUNC_VIS void * |
224 | __cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size, |
225 | void (*constructor)(void *), void (*destructor)(void *), |
226 | void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) { |
227 | const size_t heap_size = calculate_allocation_size_or_throw( |
228 | element_count, element_size, padding_size); |
229 | char* const heap_block = static_cast<char*>(alloc(heap_size)); |
230 | char* vec_base = heap_block; |
231 | |
232 | if (NULL != vec_base) { |
233 | st_heap_block3 heap(dealloc, heap_block, heap_size); |
234 | |
235 | // put the padding before the array elements |
236 | if ( 0 != padding_size ) { |
237 | vec_base += padding_size; |
238 | __set_element_count ( vec_base, element_count ); |
239 | } |
240 | |
241 | // Construct the elements |
242 | __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor ); |
243 | heap.release (); // We're good! |
244 | } |
245 | |
246 | return vec_base; |
247 | } |
248 | |
249 | |
250 | // Given the (data) addresses of a destination and a source array, an |
251 | // element count and an element size, call the given copy constructor to |
252 | // copy each element from the source array to the destination array. The |
253 | // copy constructor's arguments are the destination address and source |
254 | // address, respectively. If an exception occurs, call the given destructor |
255 | // (if non-NULL) on each copied element and rethrow. If the destructor |
256 | // throws an exception, call terminate(). The constructor and or destructor |
257 | // pointers may be NULL. If either is NULL, no action is taken when it |
258 | // would have been called. |
259 | |
260 | _LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array, |
261 | size_t element_count, |
262 | size_t element_size, |
263 | void (*constructor)(void *, void *), |
264 | void (*destructor)(void *)) { |
265 | if ( NULL != constructor ) { |
266 | size_t idx = 0; |
267 | char *src_ptr = static_cast<char *>(src_array); |
268 | char *dest_ptr = static_cast<char *>(dest_array); |
269 | st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor ); |
270 | |
271 | for ( idx = 0; idx < element_count; |
272 | ++idx, src_ptr += element_size, dest_ptr += element_size ) |
273 | constructor ( dest_ptr, src_ptr ); |
274 | cleanup.release (); // We're good! |
275 | } |
276 | } |
277 | |
278 | |
279 | // Given the (data) address of an array, not including any cookie padding, |
280 | // and the number and size of its elements, call the given constructor on |
281 | // each element. If the constructor throws an exception, call the given |
282 | // destructor for any already-constructed elements, and rethrow the |
283 | // exception. If the destructor throws an exception, call terminate(). The |
284 | // constructor and/or destructor pointers may be NULL. If either is NULL, |
285 | // no action is taken when it would have been called. |
286 | _LIBCXXABI_FUNC_VIS void |
287 | __cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size, |
288 | void (*constructor)(void *), void (*destructor)(void *)) { |
289 | if ( NULL != constructor ) { |
290 | size_t idx; |
291 | char *ptr = static_cast <char *> ( array_address ); |
292 | st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor ); |
293 | |
294 | // Construct the elements |
295 | for ( idx = 0; idx < element_count; ++idx, ptr += element_size ) |
296 | constructor ( ptr ); |
297 | cleanup.release (); // We're good! |
298 | } |
299 | } |
300 | |
301 | // Given the (data) address of an array, the number of elements, and the |
302 | // size of its elements, call the given destructor on each element. If the |
303 | // destructor throws an exception, rethrow after destroying the remaining |
304 | // elements if possible. If the destructor throws a second exception, call |
305 | // terminate(). The destructor pointer may be NULL, in which case this |
306 | // routine does nothing. |
307 | _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address, |
308 | size_t element_count, |
309 | size_t element_size, |
310 | void (*destructor)(void *)) { |
311 | if ( NULL != destructor ) { |
312 | char *ptr = static_cast <char *> (array_address); |
313 | size_t idx = element_count; |
314 | st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor ); |
315 | { |
316 | st_terminate exception_guard (__cxa_uncaught_exception ()); |
317 | ptr += element_count * element_size; // one past the last element |
318 | |
319 | while ( idx-- > 0 ) { |
320 | ptr -= element_size; |
321 | destructor ( ptr ); |
322 | } |
323 | exception_guard.release (); // We're good ! |
324 | } |
325 | cleanup.release (); // We're still good! |
326 | } |
327 | } |
328 | |
329 | // Given the (data) address of an array, the number of elements, and the |
330 | // size of its elements, call the given destructor on each element. If the |
331 | // destructor throws an exception, call terminate(). The destructor pointer |
332 | // may be NULL, in which case this routine does nothing. |
333 | _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address, |
334 | size_t element_count, |
335 | size_t element_size, |
336 | void (*destructor)(void *)) { |
337 | if ( NULL != destructor ) { |
338 | char *ptr = static_cast <char *> (array_address); |
339 | size_t idx = element_count; |
340 | st_terminate exception_guard; |
341 | |
342 | ptr += element_count * element_size; // one past the last element |
343 | while ( idx-- > 0 ) { |
344 | ptr -= element_size; |
345 | destructor ( ptr ); |
346 | } |
347 | exception_guard.release (); // We're done! |
348 | } |
349 | } |
350 | |
351 | |
352 | // If the array_address is NULL, return immediately. Otherwise, given the |
353 | // (data) address of an array, the non-negative size of prefix padding for |
354 | // the cookie, and the size of its elements, call the given destructor on |
355 | // each element, using the cookie to determine the number of elements, and |
356 | // then delete the space by calling ::operator delete[](void *). If the |
357 | // destructor throws an exception, rethrow after (a) destroying the |
358 | // remaining elements, and (b) deallocating the storage. If the destructor |
359 | // throws a second exception, call terminate(). If padding_size is 0, the |
360 | // destructor pointer must be NULL. If the destructor pointer is NULL, no |
361 | // destructor call is to be made. |
362 | // |
363 | // The intent of this function is to permit an implementation to call this |
364 | // function when confronted with an expression of the form delete[] p in |
365 | // the source code, provided that the default deallocation function can be |
366 | // used. Therefore, the semantics of this function are consistent with |
367 | // those required by the standard. The requirement that the deallocation |
368 | // function be called even if the destructor throws an exception derives |
369 | // from the resolution to DR 353 to the C++ standard, which was adopted in |
370 | // April, 2003. |
371 | _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address, |
372 | size_t element_size, |
373 | size_t padding_size, |
374 | void (*destructor)(void *)) { |
375 | __cxa_vec_delete2 ( array_address, element_size, padding_size, |
376 | destructor, &::operator delete [] ); |
377 | } |
378 | |
379 | // Same as __cxa_vec_delete, except that the given function is used for |
380 | // deallocation instead of the default delete function. If dealloc throws |
381 | // an exception, the result is undefined. The dealloc pointer may not be |
382 | // NULL. |
383 | _LIBCXXABI_FUNC_VIS void |
384 | __cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size, |
385 | void (*destructor)(void *), void (*dealloc)(void *)) { |
386 | if ( NULL != array_address ) { |
387 | char *vec_base = static_cast <char *> (array_address); |
388 | char *heap_block = vec_base - padding_size; |
389 | st_heap_block2 heap ( dealloc, heap_block ); |
390 | |
391 | if ( 0 != padding_size && NULL != destructor ) // call the destructors |
392 | __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ), |
393 | element_size, destructor ); |
394 | } |
395 | } |
396 | |
397 | |
398 | // Same as __cxa_vec_delete, except that the given function is used for |
399 | // deallocation instead of the default delete function. The deallocation |
400 | // function takes both the object address and its size. If dealloc throws |
401 | // an exception, the result is undefined. The dealloc pointer may not be |
402 | // NULL. |
403 | _LIBCXXABI_FUNC_VIS void |
404 | __cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size, |
405 | void (*destructor)(void *), void (*dealloc)(void *, size_t)) { |
406 | if ( NULL != array_address ) { |
407 | char *vec_base = static_cast <char *> (array_address); |
408 | char *heap_block = vec_base - padding_size; |
409 | const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0; |
410 | const size_t heap_block_size = element_size * element_count + padding_size; |
411 | st_heap_block3 heap ( dealloc, heap_block, heap_block_size ); |
412 | |
413 | if ( 0 != padding_size && NULL != destructor ) // call the destructors |
414 | __cxa_vec_dtor ( array_address, element_count, element_size, destructor ); |
415 | } |
416 | } |
417 | |
418 | |
419 | } // extern "C" |
420 | |
421 | } // abi |
422 | |