| 280 | // __cxa_decrement_exception_refcount has an inlined call to |
| 281 | // __cxa_free_exception. Overriding libc++ specific function |
| 282 | extern "C" BOOST_SYMBOL_EXPORT |
| 283 | void __cxa_decrement_exception_refcount(void *thrown_object) throw() { |
| 284 | BOOST_ASSERT(is_libcpp_runtime()); |
| 285 | |
| 286 | #if !defined(BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK) && defined(BOOST_HAS_THREADS) |
| 287 | static const char* leaks_are_fine = std::getenv("BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK"); |
| 288 | if (!leaks_are_fine || leaks_are_fine[0] != '1') { |
| 289 | const char* const warning = |
| 290 | "\n\n" |
| 291 | "=======================================================================================\n" |
| 292 | "\n" |
| 293 | "On this platform, memory leaks may occur if capturing stacktrace from exceptions is\n" |
| 294 | "enabled and exceptions are thrown concurrently by libc++ runtime (libc++abi).\n" |
| 295 | "\n" |
| 296 | "A proper workaround is to use libstdc++ runtime (libgcc_s) instead.\n" |
| 297 | "\n" |
| 298 | "Alternatively, if you are willing to accept potential MEMORY LEAKS, set the environment\n" |
| 299 | "variable `BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK=1` to proceed. You can\n" |
| 300 | "also define the `BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK` macro when\n" |
| 301 | "building the `boost_stacktrace_from_exception` library to disable this warning and to\n" |
| 302 | "get the MEMORY LEAKS silently on libc++ runtime.\n" |
| 303 | "\n" |
| 304 | "=======================================================================================\n" |
| 305 | ; |
| 306 | write(STDERR_FILENO, warning, std::strlen(warning)); |
| 307 | std::abort(); |
| 308 | } |
| 309 | #endif |
| 310 | |
| 311 | if (!thrown_object) { |
| 312 | return; |
| 313 | } |
| 314 | |
| 315 | static const auto orig_decrement_refcount = []() { |
| 316 | void* const ptr = ::dlsym(RTLD_NEXT, "__cxa_decrement_exception_refcount"); |
| 317 | BOOST_ASSERT_MSG(ptr, "Failed to find '__cxa_decrement_exception_refcount'"); |
| 318 | return reinterpret_cast<void(*)(void*)>(ptr); |
| 319 | }(); |
| 320 | |
| 321 | const auto* exception_header = exception_begin_llvm_ptr(thrown_object); |
| 322 | |
| 323 | // The following line has a race and could give false positives and false |
| 324 | // negatives. In first case we remove the trace earlier, in the second case |
| 325 | // we get a memory leak. |
| 326 | if (exception_header->referenceCount == 1) { |
| 327 | const std::lock_guard<std::mutex> guard{g_mapping_mutex}; |
| 328 | g_exception_to_dump_mapping.erase(thrown_object); |
| 329 | } |
| 330 | |
| 331 | orig_decrement_refcount(thrown_object); |
| 332 | } |
| 333 | |
| 334 | #endif |
| 335 |
nothing calls this directly
no test coverage detected