cxx: Add KConfig option for C++ exceptions, disable by default

Fixes https://github.com/espressif/esp-idf/issues/1072

(Additional 20KB is still used if C++ exception support is enabled in
menuconfig.)
This commit is contained in:
Angus Gratton
2017-10-04 17:29:21 +11:00
committed by Angus Gratton
parent 6f07e0797d
commit 9c7477ef34
6 changed files with 122 additions and 1 deletions

View File

@@ -1,3 +1,11 @@
# Mark __cxa_guard_dummy as undefined so that implementation of static guards
# is taken from cxx_guards.o instead of libstdc++.a
COMPONENT_ADD_LDFLAGS += -u __cxa_guard_dummy
ifndef CONFIG_CXX_EXCEPTIONS
# If exceptions are disabled, ensure our fatal exception
# hooks are preferentially linked over libstdc++ which
# has full exception support
COMPONENT_ADD_LDFLAGS += -u __cxx_fatal_exception
endif

View File

@@ -0,0 +1,87 @@
#include <cstdlib>
#include <cstdio>
#include <exception>
#include <bits/functexcept.h>
#include <sdkconfig.h>
#ifndef CONFIG_CXX_EXCEPTIONS
const char *FATAL_EXCEPTION = "Fatal C++ exception: ";
extern "C" void __cxx_fatal_exception(void)
{
abort();
}
extern "C" void __cxx_fatal_exception_message(const char *msg)
{
printf("%s%s\n", FATAL_EXCEPTION, msg);
abort();
}
extern "C" void __cxx_fatal_exception_int(int i)
{
printf("%s (%d)\n", FATAL_EXCEPTION, i);
abort();
}
void std::__throw_bad_exception(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_bad_alloc(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_bad_cast(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_bad_typeid(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_logic_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_domain_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_invalid_argument(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_length_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_out_of_range(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_out_of_range_fmt(const char*, ...) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_runtime_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_range_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_overflow_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_underflow_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_ios_failure(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_system_error(int) __attribute__((alias("__cxx_fatal_exception_int")));
void std::__throw_bad_function_call(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_future_error(int) __attribute__((alias("__cxx_fatal_exception_int")));
/* The following definitions are needed because libstdc++ is also compiled with
__throw_exception_again defined to throw, and some other exception code in a few places.
This cause exception handler code to be emitted in the library even though it's mostly
unreachable (as any libstdc++ "throw" will first call one of the above stubs, which will abort).
If these are left out, a bunch of unwanted exception handler code is linked.
Note: these function prototypes are not correct.
*/
extern "C" void __cxa_allocate_exception(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_begin_catch(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_end_catch(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_get_exception_ptr(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_free_exception(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_rethrow(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_throw(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_call_terminate(void) __attribute__((alias("__cxx_fatal_exception")));
bool std::uncaught_exception() __attribute__((alias("__cxx_fatal_exception")));
#endif // CONFIG_CXX_EXCEPTIONS

View File

@@ -188,8 +188,12 @@ TEST_CASE("before scheduler has started, static initializers work correctly", "[
TEST_ASSERT_EQUAL(2, StaticInitTestBeforeScheduler::order);
}
#ifdef CONFIG_CXX_EXCEPTIONS
TEST_CASE("c++ exceptions work", "[cxx]")
{
/* Note: This test currently trips the memory leak threshold
as libunwind allocates ~4KB of data on first exception. */
int thrown_value;
try
{
@@ -203,6 +207,8 @@ TEST_CASE("c++ exceptions work", "[cxx]")
printf("OK?\n");
}
#endif
/* These test cases pull a lot of code from libstdc++ and are disabled for now
*/
#if 0