Merge branch 'feature/cxx_exceptions_emg_pool' into 'master'

esp32: Adds C++ exceptions emergency pool size menuconfig option

See merge request !1561
This commit is contained in:
Ivan Grokhotkov 2017-11-23 13:02:49 +08:00
commit b669b415e6
3 changed files with 80 additions and 6 deletions

14
Kconfig
View File

@ -93,7 +93,7 @@ config OPTIMIZATION_ASSERTIONS_DISABLED
endchoice # assertions endchoice # assertions
config CXX_EXCEPTIONS menuconfig CXX_EXCEPTIONS
bool "Enable C++ exceptions" bool "Enable C++ exceptions"
default n default n
help help
@ -102,8 +102,16 @@ config CXX_EXCEPTIONS
Disabling this option disables C++ exception support in all compiled files, and any libstdc++ code which throws Disabling this option disables C++ exception support in all compiled files, and any libstdc++ code which throws
an exception will abort instead. an exception will abort instead.
Enabling this option currently adds an additional 20KB of heap overhead, and 4KB of additional heap is allocated Enabling this option currently adds an additional ~500 bytes of heap overhead
the first time an exception is thrown in user code. when an exception is thrown in user code for the first time.
config CXX_EXCEPTIONS_EMG_POOL_SIZE
int "Emergency Pool Size"
default 0
depends on CXX_EXCEPTIONS
help
Size (in bytes) of the emergency memory pool for C++ exceptions. This pool will be used to allocate
memory for thrown exceptions when there is not enough memory on the heap.
choice STACK_CHECK_MODE choice STACK_CHECK_MODE
prompt "Stack smashing protection mode" prompt "Stack smashing protection mode"

View File

@ -20,7 +20,7 @@ class Base
{ {
public: public:
virtual ~Base() {} virtual ~Base() {}
virtual void foo() = 0; virtual void foo() = 0;
}; };
class Derived : public Base class Derived : public Base
@ -192,8 +192,13 @@ TEST_CASE("before scheduler has started, static initializers work correctly", "[
TEST_CASE("c++ exceptions work", "[cxx]") TEST_CASE("c++ exceptions work", "[cxx]")
{ {
/* Note: This test currently trips the memory leak threshold /* Note: When first exception (in system) is thrown this test produces memory leaks report (~500 bytes):
as libunwind allocates ~4KB of data on first exception. */ - 392 bytes (can vary) as libunwind allocates memory to keep stack frames info to handle exceptions.
This info is kept until global destructors are called by __do_global_dtors_aux()
- 8 bytes are allocated by __cxa_get_globals() to keep __cxa_eh_globals
- 16 bytes are allocated by pthread_setspecific() which is called by __cxa_get_globals() to init TLS var for __cxa_eh_globals
- 88 bytes are allocated by pthread_setspecific() to init internal lock
*/
int thrown_value; int thrown_value;
try try
{ {
@ -207,6 +212,60 @@ TEST_CASE("c++ exceptions work", "[cxx]")
printf("OK?\n"); printf("OK?\n");
} }
TEST_CASE("c++ exceptions emergency pool", "[cxx] [ignore]")
{
/* Note: When first exception (in system) is thrown this test produces memory leaks report (~500 bytes):
- 392 bytes (can vary) as libunwind allocates memory to keep stack frames info to handle exceptions.
This info is kept until global destructors are called by __do_global_dtors_aux()
- 8 bytes are allocated by __cxa_get_globals() to keep __cxa_eh_globals
- 16 bytes are allocated by pthread_setspecific() which is called by __cxa_get_globals() to init TLS var for __cxa_eh_globals
- 88 bytes are allocated by pthread_setspecific() to init internal lock
*/
void **p, **pprev = NULL;
int thrown_value = 0;
// throw first exception to ensure that all initial allocations are made
try
{
throw 33;
}
catch (int e)
{
thrown_value = e;
}
TEST_ASSERT_EQUAL(33, thrown_value);
// consume all dynamic memory
while ((p = (void **)malloc(sizeof(void *)))) {
if (pprev) {
*p = pprev;
} else {
*p = NULL;
}
pprev = p;
}
try
{
throw 20;
}
catch (int e)
{
thrown_value = e;
printf("Got exception %d\n", thrown_value);
}
#if CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE > 0
// free all memory
while (pprev) {
p = (void **)(*pprev);
free(pprev);
pprev = p;
}
TEST_ASSERT_EQUAL(20, thrown_value);
#else
// if emergency pool is disabled we should never get here,
// expect abort() due to lack of memory for new exception
TEST_ASSERT_TRUE(0 == 1);
#endif
}
#endif #endif
/* These test cases pull a lot of code from libstdc++ and are disabled for now /* These test cases pull a lot of code from libstdc++ and are disabled for now

View File

@ -397,6 +397,13 @@ void start_cpu1_default(void)
} }
#endif //!CONFIG_FREERTOS_UNICORE #endif //!CONFIG_FREERTOS_UNICORE
#ifdef CONFIG_CXX_EXCEPTIONS
size_t __cxx_eh_arena_size_get()
{
return CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE;
}
#endif
static void do_global_ctors(void) static void do_global_ctors(void)
{ {
#ifdef CONFIG_CXX_EXCEPTIONS #ifdef CONFIG_CXX_EXCEPTIONS