1 // New abi Support -*- C++ -*-
2 
3 // Copyright (C) 2000-2022 Free Software Foundation, Inc.
4 //
5 // This file is part of GCC.
6 //
7 // GCC is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11 
12 // GCC is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20 
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 // <http://www.gnu.org/licenses/>.
25 
26 // Written by Nathan Sidwell, Codesourcery LLC, <nathan@codesourcery.com>
27 
28 #include <cxxabi.h>
29 #include <new>
30 #include <exception>
31 #include <bits/exception_defines.h>
32 #include "unwind-cxx.h"
33 
34 namespace __cxxabiv1
35 {
36   namespace
37   {
38     struct uncatch_exception
39     {
40       uncatch_exception();
~uncatch_exception__cxxabiv1::__anona030657c0111::uncatch_exception41       ~uncatch_exception () { __cxa_begin_catch (&p->unwindHeader); }
42 
43       __cxa_exception* p;
44 
45     private:
46       uncatch_exception&
47       operator=(const uncatch_exception&);
48 
49       uncatch_exception(const uncatch_exception&);
50     };
51 
uncatch_exception()52     uncatch_exception::uncatch_exception() : p(0)
53     {
54       __cxa_eh_globals *globals = __cxa_get_globals_fast ();
55 
56       p = globals->caughtExceptions;
57       p->handlerCount -= 1;
58       globals->caughtExceptions = p->nextException;
59       globals->uncaughtExceptions += 1;
60     }
61 
62     // Compute the total size with overflow checking.
compute_size(std::size_t element_count,std::size_t element_size,std::size_t padding_size)63     std::size_t compute_size(std::size_t element_count,
64                                    std::size_t element_size,
65                                    std::size_t padding_size)
66     {
67       if (element_size && element_count > std::size_t(-1) / element_size)
68           _GLIBCXX_THROW_OR_ABORT(std::bad_alloc());
69       std::size_t size = element_count * element_size;
70       if (size + padding_size < size)
71           _GLIBCXX_THROW_OR_ABORT(std::bad_alloc());
72       return size + padding_size;
73     }
74   }
75 
76   // Allocate and construct array.
77   extern "C" void *
__cxa_vec_new(std::size_t element_count,std::size_t element_size,std::size_t padding_size,__cxa_cdtor_type constructor,__cxa_cdtor_type destructor)78   __cxa_vec_new(std::size_t element_count,
79                     std::size_t element_size,
80                     std::size_t padding_size,
81                     __cxa_cdtor_type constructor,
82                     __cxa_cdtor_type destructor)
83   {
84     return __cxa_vec_new2(element_count, element_size, padding_size,
85                                  constructor, destructor,
86                                  &operator new[], &operator delete []);
87   }
88 
89   extern "C" void *
__cxa_vec_new2(std::size_t element_count,std::size_t element_size,std::size_t padding_size,__cxa_cdtor_type constructor,__cxa_cdtor_type destructor,void * (* alloc)(std::size_t),void (* dealloc)(void *))90   __cxa_vec_new2(std::size_t element_count,
91                      std::size_t element_size,
92                      std::size_t padding_size,
93                      __cxa_cdtor_type constructor,
94                      __cxa_cdtor_type destructor,
95                      void *(*alloc) (std::size_t),
96                      void (*dealloc) (void *))
97   {
98     std::size_t size
99       = compute_size(element_count, element_size, padding_size);
100     char *base = static_cast <char *> (alloc (size));
101     if (!base)
102       return base;
103 
104     if (padding_size)
105       {
106           base += padding_size;
107           reinterpret_cast <std::size_t *> (base)[-1] = element_count;
108 #ifdef _GLIBCXX_ELTSIZE_IN_COOKIE
109           reinterpret_cast <std::size_t *> (base)[-2] = element_size;
110 #endif
111       }
112     __try
113       {
114           __cxa_vec_ctor(base, element_count, element_size,
115                            constructor, destructor);
116       }
117     __catch(...)
118       {
119           {
120             uncatch_exception ue;
121             // Core issue 901 will probably be resolved such that a
122             // deleted operator delete means not freeing memory here.
123             if (dealloc)
124               dealloc(base - padding_size);
125           }
126           __throw_exception_again;
127       }
128     return base;
129   }
130 
131   extern "C" void *
__cxa_vec_new3(std::size_t element_count,std::size_t element_size,std::size_t padding_size,__cxa_cdtor_type constructor,__cxa_cdtor_type destructor,void * (* alloc)(std::size_t),void (* dealloc)(void *,std::size_t))132   __cxa_vec_new3(std::size_t element_count,
133                      std::size_t element_size,
134                      std::size_t padding_size,
135                      __cxa_cdtor_type constructor,
136                      __cxa_cdtor_type destructor,
137                      void *(*alloc) (std::size_t),
138                      void (*dealloc) (void *, std::size_t))
139   {
140     std::size_t size
141       = compute_size(element_count, element_size, padding_size);
142     char *base = static_cast<char *>(alloc (size));
143     if (!base)
144       return base;
145 
146     if (padding_size)
147       {
148           base += padding_size;
149           reinterpret_cast<std::size_t *>(base)[-1] = element_count;
150 #ifdef _GLIBCXX_ELTSIZE_IN_COOKIE
151           reinterpret_cast <std::size_t *> (base)[-2] = element_size;
152 #endif
153       }
154     __try
155       {
156           __cxa_vec_ctor(base, element_count, element_size,
157                            constructor, destructor);
158       }
159     __catch(...)
160       {
161           {
162             uncatch_exception ue;
163             if (dealloc)
164               dealloc(base - padding_size, size);
165           }
166           __throw_exception_again;
167       }
168     return base;
169   }
170 
171   // Construct array.
172   extern "C" __cxa_vec_ctor_return_type
__cxa_vec_ctor(void * array_address,std::size_t element_count,std::size_t element_size,__cxa_cdtor_type constructor,__cxa_cdtor_type destructor)173   __cxa_vec_ctor(void *array_address,
174                      std::size_t element_count,
175                      std::size_t element_size,
176                      __cxa_cdtor_type constructor,
177                      __cxa_cdtor_type destructor)
178   {
179     std::size_t ix = 0;
180     char *ptr = static_cast<char *>(array_address);
181 
182     __try
183       {
184           if (constructor)
185             for (; ix != element_count; ix++, ptr += element_size)
186               constructor(ptr);
187       }
188     __catch(...)
189       {
190           {
191             uncatch_exception ue;
192             __cxa_vec_cleanup(array_address, ix, element_size, destructor);
193           }
194           __throw_exception_again;
195       }
196     _GLIBCXX_CXA_VEC_CTOR_RETURN (array_address);
197   }
198 
199   // Construct an array by copying.
200   extern "C" __cxa_vec_ctor_return_type
__cxa_vec_cctor(void * dest_array,void * src_array,std::size_t element_count,std::size_t element_size,__cxa_cdtor_return_type (* constructor)(void *,void *),__cxa_cdtor_type destructor)201   __cxa_vec_cctor(void *dest_array,
202                       void *src_array,
203                       std::size_t element_count,
204                       std::size_t element_size,
205                       __cxa_cdtor_return_type (*constructor) (void *, void *),
206                       __cxa_cdtor_type destructor)
207   {
208     std::size_t ix = 0;
209     char *dest_ptr = static_cast<char *>(dest_array);
210     char *src_ptr = static_cast<char *>(src_array);
211 
212     __try
213       {
214           if (constructor)
215             for (; ix != element_count;
216                  ix++, src_ptr += element_size, dest_ptr += element_size)
217               constructor(dest_ptr, src_ptr);
218       }
219     __catch(...)
220       {
221           {
222             uncatch_exception ue;
223             __cxa_vec_cleanup(dest_array, ix, element_size, destructor);
224           }
225           __throw_exception_again;
226       }
227     _GLIBCXX_CXA_VEC_CTOR_RETURN (dest_array);
228   }
229 
230   // Destruct array.
231   extern "C" void
__cxa_vec_dtor(void * array_address,std::size_t element_count,std::size_t element_size,__cxa_cdtor_type destructor)232   __cxa_vec_dtor(void *array_address,
233                      std::size_t element_count,
234                      std::size_t element_size,
235                      __cxa_cdtor_type destructor)
236   {
237     if (destructor)
238       {
239           char *ptr = static_cast<char *>(array_address);
240           std::size_t ix = element_count;
241 
242           ptr += element_count * element_size;
243 
244           __try
245             {
246               while (ix--)
247                 {
248                     ptr -= element_size;
249                     destructor(ptr);
250                 }
251             }
252           __catch(...)
253             {
254               {
255                 uncatch_exception ue;
256                 __cxa_vec_cleanup(array_address, ix, element_size, destructor);
257               }
258               __throw_exception_again;
259             }
260       }
261   }
262 
263   // Destruct array as a result of throwing an exception.
264   // [except.ctor]/3 If a destructor called during stack unwinding
265   // exits with an exception, terminate is called.
266   extern "C" void
__cxa_vec_cleanup(void * array_address,std::size_t element_count,std::size_t element_size,__cxa_cdtor_type destructor)267   __cxa_vec_cleanup(void *array_address,
268                         std::size_t element_count,
269                         std::size_t element_size,
270                         __cxa_cdtor_type destructor) throw()
271   {
272     if (destructor)
273       {
274           char *ptr = static_cast <char *> (array_address);
275           std::size_t ix = element_count;
276 
277           ptr += element_count * element_size;
278 
279           __try
280             {
281               while (ix--)
282                 {
283                     ptr -= element_size;
284                     destructor(ptr);
285                 }
286             }
287           __catch(...)
288             {
289               std::terminate();
290             }
291       }
292   }
293 
294   // Destruct and release array.
295   extern "C" void
__cxa_vec_delete(void * array_address,std::size_t element_size,std::size_t padding_size,__cxa_cdtor_type destructor)296   __cxa_vec_delete(void *array_address,
297                        std::size_t element_size,
298                        std::size_t padding_size,
299                        __cxa_cdtor_type destructor)
300   {
301     __cxa_vec_delete2(array_address, element_size, padding_size,
302                            destructor,
303                            &operator delete []);
304   }
305 
306   extern "C" void
__cxa_vec_delete2(void * array_address,std::size_t element_size,std::size_t padding_size,__cxa_cdtor_type destructor,void (* dealloc)(void *))307   __cxa_vec_delete2(void *array_address,
308                         std::size_t element_size,
309                         std::size_t padding_size,
310                         __cxa_cdtor_type destructor,
311                         void (*dealloc) (void *))
312   {
313     if (!array_address)
314       return;
315 
316     char* base = static_cast<char *>(array_address);
317 
318     if (padding_size)
319       {
320           std::size_t element_count = reinterpret_cast<std::size_t *>(base)[-1];
321           base -= padding_size;
322           __try
323             {
324               __cxa_vec_dtor(array_address, element_count, element_size,
325                                  destructor);
326             }
327           __catch(...)
328             {
329               {
330                 uncatch_exception ue;
331                 dealloc(base);
332               }
333               __throw_exception_again;
334             }
335       }
336     dealloc(base);
337   }
338 
339   extern "C" void
__cxa_vec_delete3(void * array_address,std::size_t element_size,std::size_t padding_size,__cxa_cdtor_type destructor,void (* dealloc)(void *,std::size_t))340   __cxa_vec_delete3(void *array_address,
341                         std::size_t element_size,
342                         std::size_t padding_size,
343                          __cxa_cdtor_type destructor,
344                         void (*dealloc) (void *, std::size_t))
345   {
346     if (!array_address)
347       return;
348 
349     char* base = static_cast <char *> (array_address);
350     std::size_t size = 0;
351 
352     if (padding_size)
353       {
354           std::size_t element_count = reinterpret_cast<std::size_t *> (base)[-1];
355           base -= padding_size;
356           size = element_count * element_size + padding_size;
357           __try
358             {
359               __cxa_vec_dtor(array_address, element_count, element_size,
360                                  destructor);
361             }
362           __catch(...)
363             {
364               {
365                 uncatch_exception ue;
366                 dealloc(base, size);
367               }
368               __throw_exception_again;
369             }
370       }
371     dealloc(base, size);
372   }
373 } // namespace __cxxabiv1
374 
375 #if defined(__arm__) && defined(__ARM_EABI__)
376 
377 // The ARM C++ ABI requires that the library provide these additional
378 // helper functions.  There are placed in this file, despite being
379 // architecture-specifier, so that the compiler can inline the __cxa
380 // functions into these functions as appropriate.
381 
382 namespace __aeabiv1
383 {
384   extern "C" void *
__aeabi_vec_ctor_nocookie_nodtor(void * array_address,abi::__cxa_cdtor_type constructor,std::size_t element_size,std::size_t element_count)385   __aeabi_vec_ctor_nocookie_nodtor (void *array_address,
386                                             abi::__cxa_cdtor_type constructor,
387                                             std::size_t element_size,
388                                             std::size_t element_count)
389   {
390     return abi::__cxa_vec_ctor (array_address, element_count, element_size,
391                                         constructor, /*destructor=*/NULL);
392   }
393 
394   extern "C" void *
__aeabi_vec_ctor_cookie_nodtor(void * array_address,abi::__cxa_cdtor_type constructor,std::size_t element_size,std::size_t element_count)395   __aeabi_vec_ctor_cookie_nodtor (void *array_address,
396                                           abi::__cxa_cdtor_type constructor,
397                                           std::size_t element_size,
398                                           std::size_t element_count)
399   {
400     if (array_address == NULL)
401       return NULL;
402 
403     array_address = reinterpret_cast<std::size_t *>(array_address) + 2;
404     reinterpret_cast<std::size_t *>(array_address)[-2] = element_size;
405     reinterpret_cast<std::size_t *>(array_address)[-1] = element_count;
406     return abi::__cxa_vec_ctor (array_address,
407                                         element_count, element_size,
408                                         constructor, /*destructor=*/NULL);
409   }
410 
411   extern "C" void *
__aeabi_vec_cctor_nocookie_nodtor(void * dest_array,void * src_array,std::size_t element_size,std::size_t element_count,void * (* constructor)(void *,void *))412   __aeabi_vec_cctor_nocookie_nodtor (void *dest_array,
413                                              void *src_array,
414                                              std::size_t element_size,
415                                              std::size_t element_count,
416                                              void *(*constructor) (void *, void *))
417   {
418     return abi::__cxa_vec_cctor (dest_array, src_array,
419                                          element_count, element_size,
420                                          constructor, NULL);
421   }
422 
423   extern "C" void *
__aeabi_vec_new_cookie_noctor(std::size_t element_size,std::size_t element_count)424   __aeabi_vec_new_cookie_noctor (std::size_t element_size,
425                                          std::size_t element_count)
426   {
427     return abi::__cxa_vec_new(element_count, element_size,
428                                     2 * sizeof (std::size_t),
429                                     /*constructor=*/NULL, /*destructor=*/NULL);
430   }
431 
432   extern "C" void *
__aeabi_vec_new_nocookie(std::size_t element_size,std::size_t element_count,abi::__cxa_cdtor_type constructor)433   __aeabi_vec_new_nocookie (std::size_t element_size,
434                                   std::size_t element_count,
435                                   abi::__cxa_cdtor_type constructor)
436   {
437     return abi::__cxa_vec_new (element_count, element_size, 0, constructor,
438                                      NULL);
439   }
440 
441   extern "C" void *
__aeabi_vec_new_cookie_nodtor(std::size_t element_size,std::size_t element_count,abi::__cxa_cdtor_type constructor)442   __aeabi_vec_new_cookie_nodtor (std::size_t element_size,
443                                          std::size_t element_count,
444                                          abi::__cxa_cdtor_type constructor)
445   {
446     return abi::__cxa_vec_new(element_count, element_size,
447                                     2 * sizeof (std::size_t),
448                                     constructor, NULL);
449   }
450 
451   extern "C" void *
__aeabi_vec_new_cookie(std::size_t element_size,std::size_t element_count,abi::__cxa_cdtor_type constructor,abi::__cxa_cdtor_type destructor)452   __aeabi_vec_new_cookie(std::size_t element_size,
453                                std::size_t element_count,
454                                abi::__cxa_cdtor_type constructor,
455                                abi::__cxa_cdtor_type destructor)
456   {
457     return abi::__cxa_vec_new (element_count, element_size,
458                                      2 * sizeof (std::size_t),
459                                      constructor, destructor);
460   }
461 
462 
463   extern "C" void *
__aeabi_vec_dtor(void * array_address,abi::__cxa_cdtor_type destructor,std::size_t element_size,std::size_t element_count)464   __aeabi_vec_dtor (void *array_address,
465                         abi::__cxa_cdtor_type destructor,
466                         std::size_t element_size,
467                         std::size_t element_count)
468   {
469     abi::__cxa_vec_dtor (array_address, element_count, element_size,
470                                destructor);
471     return reinterpret_cast<std::size_t*> (array_address) - 2;
472   }
473 
474   extern "C" void *
__aeabi_vec_dtor_cookie(void * array_address,abi::__cxa_cdtor_type destructor)475   __aeabi_vec_dtor_cookie (void *array_address,
476                                  abi::__cxa_cdtor_type destructor)
477   {
478     if (!array_address)
479       return NULL;
480 
481     abi::__cxa_vec_dtor (array_address,
482                                reinterpret_cast<std::size_t *>(array_address)[-1],
483                                reinterpret_cast<std::size_t *>(array_address)[-2],
484                                destructor);
485     return reinterpret_cast<std::size_t*> (array_address) - 2;
486   }
487 
488 
489   extern "C" void
__aeabi_vec_delete(void * array_address,abi::__cxa_cdtor_type destructor)490   __aeabi_vec_delete (void *array_address,
491                           abi::__cxa_cdtor_type destructor)
492   {
493     if (!array_address)
494       return;
495 
496     abi::__cxa_vec_delete (array_address,
497                                  reinterpret_cast<std::size_t *>(array_address)[-2],
498                                  2 * sizeof (std::size_t),
499                                  destructor);
500   }
501 
502   extern "C" void
__aeabi_vec_delete3(void * array_address,abi::__cxa_cdtor_type destructor,void (* dealloc)(void *,std::size_t))503   __aeabi_vec_delete3 (void *array_address,
504                            abi::__cxa_cdtor_type destructor,
505                            void (*dealloc) (void *, std::size_t))
506   {
507     if (!array_address)
508       return;
509 
510     abi::__cxa_vec_delete3 (array_address,
511                                   reinterpret_cast<std::size_t *>(array_address)[-2],
512                                   2 * sizeof (std::size_t),
513                                   destructor, dealloc);
514   }
515 
516   extern "C" void
__aeabi_vec_delete3_nodtor(void * array_address,void (* dealloc)(void *,std::size_t))517   __aeabi_vec_delete3_nodtor (void *array_address,
518                                     void (*dealloc) (void *, std::size_t))
519   {
520     if (!array_address)
521       return;
522 
523     abi::__cxa_vec_delete3 (array_address,
524                                   reinterpret_cast<std::size_t *>(array_address)[-2],
525                                   2 * sizeof (std::size_t),
526                                   /*destructor=*/NULL, dealloc);
527   }
528 } // namespace __aeabiv1
529 
530 #endif // defined(__arm__) && defined(__ARM_EABI__)
531