endchoice # assertions
-config CXX_EXCEPTIONS
+menuconfig CXX_EXCEPTIONS
bool "Enable C++ exceptions"
default n
help
Disabling this option disables C++ exception support in all compiled files, and any libstdc++ code which throws
an exception will abort instead.
- Enabling this option currently adds an additional 20KB of heap overhead, and 4KB of additional heap is allocated
- the first time an exception is thrown in user code.
+ Enabling this option currently adds an additional ~500 bytes of heap overhead
+ 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.
endmenu # Compiler Options
{
public:
virtual ~Base() {}
- virtual void foo() = 0;
+ virtual void foo() = 0;
};
class Derived : public Base
TEST_CASE("c++ exceptions work", "[cxx]")
{
- /* Note: This test currently trips the memory leak threshold
- as libunwind allocates ~4KB of data on first exception. */
+ /* 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
+ */
int thrown_value;
try
{
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
/* These test cases pull a lot of code from libstdc++ and are disabled for now