This patch allows the size of the emergency buffer for exception handling to be controlled by a build-time macro (to avoid dynamic allocation) or by a run-time environment variable (to allocate a larger or smaller buffer).
This will have to wait for the next stage 1 now, as it's too late for GCC 7, but this shows what I'm thinking about and so might avoid anybody else reinventing the wheel. The patch doesn't include documentation updates for the manual, which would be needed to explain the use of the macro and the env var. We could also add a --with-libstdcxx-static-eh-pool=N configure flag to make it easier to set the macro.
commit 4e021613dcda14dfec5c88286f8faf3001afcd17 Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue Dec 13 13:23:48 2016 +0000 Allow pool size to be set by macro or env var diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac index 7d0fafa..be4679e 100644 --- a/libstdc++-v3/configure.ac +++ b/libstdc++-v3/configure.ac @@ -257,6 +257,7 @@ if $GLIBCXX_IS_NATIVE; then AC_CHECK_FUNCS(__cxa_thread_atexit_impl) AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) + AC_CHECK_FUNCS(secure_getenv) # For iconv support. AM_ICONV diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4 index 8cc788c..c01213a 100644 --- a/libstdc++-v3/crossconfig.m4 +++ b/libstdc++-v3/crossconfig.m4 @@ -184,6 +184,7 @@ case "${host}" in GCC_CHECK_TLS AC_CHECK_FUNCS(__cxa_thread_atexit_impl) AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) + AC_CHECK_FUNCS(secure_getenv) AM_ICONV ;; *-mingw32*) diff --git a/libstdc++-v3/libsupc++/eh_alloc.cc b/libstdc++-v3/libsupc++/eh_alloc.cc index d362e40..571fe6b 100644 --- a/libstdc++-v3/libsupc++/eh_alloc.cc +++ b/libstdc++-v3/libsupc++/eh_alloc.cc @@ -29,6 +29,7 @@ #include <cstdlib> #if _GLIBCXX_HOSTED #include <cstring> +#include <cerrno> #endif #include <climits> #include <exception> @@ -36,6 +37,14 @@ #include <ext/concurrence.h> #include <new> +#ifdef STATIC_EH_ALLOC_POOL_BYTES +char* alloc_pool_arena(std::size_t& size) +{ + size = STATIC_EH_ALLOC_POOL_BYTES; + static alignas(void*) char arena[STATIC_EH_ALLOC_POOL_BYTES]; + return arena; +} +#else #if _GLIBCXX_HOSTED using std::free; using std::malloc; @@ -50,8 +59,6 @@ extern "C" void *memset (void *, int, std::size_t); using namespace __cxxabiv1; -// ??? How to control these parameters. - // Guess from the size of basic types how large a buffer is reasonable. // Note that the basic c++ exception header has 13 pointers and 2 ints, // so on a system with PSImode pointers we're talking about 56 bytes @@ -73,6 +80,32 @@ using namespace __cxxabiv1; # define EMERGENCY_OBJ_COUNT 4 #endif +char *alloc_pool_arena(std::size_t& size) +{ + size = 0; +#if _GLIBCXX_HOSTED + const char *name = "GLIBCXX_EH_ARENA_SIZE"; + char *env = nullptr; +# ifdef _GLIBCXX_HAVE_SECURE_GETENV + env = ::secure_getenv (name); +# else + env = std::getenv (name); +# endif + if (env) + { + char *end; + size = strtoul(env, &end, 0); + if (*end || (size == ULONG_MAX && errno == ERANGE)) + size = 0; + } +#endif // _GLIBCXX_HOSTED + if (size == 0) + size = (EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT + + EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception)); + return (char *)malloc (size); +} +#endif // STATIC_EH_ALLOC_POOL_BYTES + namespace __gnu_cxx { void __freeres(); @@ -107,7 +140,7 @@ namespace // The free-list free_entry *first_free_entry; // The arena itself - we need to keep track of these only - // to implement in_pool. + // to implement in_pool and __freeres. char *arena; std::size_t arena_size; @@ -116,11 +149,8 @@ namespace pool::pool() { - // Allocate the arena - we could add a GLIBCXX_EH_ARENA_SIZE environment - // to make this tunable. - arena_size = (EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT - + EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception)); - arena = (char *)malloc (arena_size); + // Allocate the arena. + arena = alloc_pool_arena (arena_size); if (!arena) { // If the allocation failed go without an emergency pool. @@ -255,11 +285,13 @@ namespace __gnu_cxx void __freeres() { +#ifndef STATIC_EH_ALLOC_POOL_BYTES if (emergency_pool.arena) { ::free(emergency_pool.arena); emergency_pool.arena = 0; } +#endif } }