Skip to content

Commit 0791d5d

Browse files
committed
init libsupc++ emergency_pool early
When an exception is thrown and caught, destruction of the exception checks whether the exception was allocated in the `emergency_pool`, which is a global variable. This global variable has a runtime constructor, which means access to it is valid only once the constructor has run during the module init phase. But throwing and catching an exception is permitted at any time, not just during the lifetime of `main`. And this must be true whether libsupc++ is linked dynamically or statically. LLVM Address Sanitizer aborts with `initialization-order-fiasco` when, in a binary which links libsupc++ statically, an exception is thrown and caught in some global constructor which happens to run prior to the global constructor of `emergency_pool`. ``` ERROR: AddressSanitizer: initialization-order-fiasco ... READ of size 8 at ... thread T0 SCARINESS: 14 (8-byte-read-initialization-order-fiasco) #0 ... in (anonymous namespace)::pool::in_pool(void*) gcc-11.x/libstdc++-v3/libsupc++/eh_alloc.cc:258 gcc-mirror#1 ... in __cxa_free_exception gcc-11.x/libstdc++-v3/libsupc++/eh_alloc.cc:302 gcc-mirror#2 ... in __gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Exception*) gcc-11.x/libstdc++-v3/libsupc++/eh_throw.cc:51 gcc-mirror#3 ... in __cxa_end_catch gcc-11.x/libstdc++-v3/libsupc++/eh_catch.cc:125 ... ... in __cxx_global_var_init ... ... ... in call_init.part.0 glibc-2.40/elf/dl-init.c:74:3 ... in call_init glibc-2.40/elf/dl-init.c:120:14 ... in _dl_init glibc-2.40/elf/dl-init.c:121:5 ... in _dl_start_user glibc-2.40/elf/../sysdeps/aarch64/dl-start.S:46 ... is located 56 bytes inside of global variable '(anonymous namespace)::emergency_pool' defined in 'gcc-11.x/libstdc++-v3/libsupc++/eh_alloc.cc' (...) of size 72 registered at: #0 ... in __asan_register_globals.part.0 llvm-project/compiler-rt/lib/asan/asan_globals.cpp:393:3 gcc-mirror#1 ... in __asan_register_globals llvm-project/compiler-rt/lib/asan/asan_globals.cpp:392:3 gcc-mirror#2 ... in __asan_register_elf_globals llvm-project/compiler-rt/lib/asan/asan_globals.cpp:376:26 gcc-mirror#3 ... in call_init.part.0 glibc-2.40/elf/dl-init.c:74:3 gcc-mirror#4 ... in call_init glibc-2.40/elf/dl-init.c:120:14 gcc-mirror#5 ... in _dl_init glibc-2.40/elf/dl-init.c:121:5 gcc-mirror#6 ... in _dl_start_user glibc-2.40/elf/../sysdeps/aarch64/dl-start.S:46 ```
1 parent 2954038 commit 0791d5d

File tree

1 file changed

+30
-10
lines changed

1 file changed

+30
-10
lines changed

libstdc++-v3/libsupc++/eh_alloc.cc

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,27 @@ namespace
370370
return less(ptr, arena + arena_size) && less(arena, ptr);
371371
}
372372

373-
pool emergency_pool;
373+
struct pool_storage {
374+
alignas(pool) unsigned char storage[sizeof(pool)];
375+
bool init = false;
376+
};
377+
378+
pool_storage emergency_pool_storage;
379+
380+
__attribute__((__pure__))
381+
pool& emergency_pool() {
382+
auto& obj = emergency_pool_storage;
383+
if (!obj.init, 0) [[__unlikely__]] {
384+
new (obj.storage) pool;
385+
obj.init = true;
386+
}
387+
return *reinterpret_cast<pool*>(obj.storage);
388+
}
389+
390+
__attribute__((__constructor__(102)))
391+
void init_emergency_pool() noexcept {
392+
(void)emergency_pool();
393+
}
374394
}
375395

376396
namespace __gnu_cxx
@@ -380,10 +400,10 @@ namespace __gnu_cxx
380400
__freeres() noexcept
381401
{
382402
#ifndef _GLIBCXX_EH_POOL_STATIC
383-
if (emergency_pool.arena)
403+
if (emergency_pool().arena)
384404
{
385-
::free(emergency_pool.arena);
386-
emergency_pool.arena = 0;
405+
::free(emergency_pool().arena);
406+
emergency_pool().arena = 0;
387407
}
388408
#endif
389409
}
@@ -399,7 +419,7 @@ __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) noexcept
399419

400420
#if USE_POOL
401421
if (!ret)
402-
ret = emergency_pool.allocate (thrown_size);
422+
ret = emergency_pool().allocate (thrown_size);
403423
#endif
404424

405425
if (!ret)
@@ -416,8 +436,8 @@ __cxxabiv1::__cxa_free_exception(void *vptr) noexcept
416436
{
417437
char *ptr = (char *) vptr - sizeof (__cxa_refcounted_exception);
418438
#if USE_POOL
419-
if (emergency_pool.in_pool (ptr)) [[__unlikely__]]
420-
emergency_pool.free (ptr);
439+
if (emergency_pool().in_pool (ptr)) [[__unlikely__]]
440+
emergency_pool().free (ptr);
421441
else
422442
#endif
423443
free (ptr);
@@ -431,7 +451,7 @@ __cxxabiv1::__cxa_allocate_dependent_exception() noexcept
431451

432452
#if USE_POOL
433453
if (!ret)
434-
ret = emergency_pool.allocate (sizeof (__cxa_dependent_exception));
454+
ret = emergency_pool().allocate (sizeof (__cxa_dependent_exception));
435455
#endif
436456

437457
if (!ret)
@@ -448,8 +468,8 @@ __cxxabiv1::__cxa_free_dependent_exception
448468
(__cxa_dependent_exception *vptr) noexcept
449469
{
450470
#if USE_POOL
451-
if (emergency_pool.in_pool (vptr)) [[__unlikely__]]
452-
emergency_pool.free (vptr);
471+
if (emergency_pool().in_pool (vptr)) [[__unlikely__]]
472+
emergency_pool().free (vptr);
453473
else
454474
#endif
455475
free (vptr);

0 commit comments

Comments
 (0)