As the PR points out, the constructor called in the placement new expression can throw, in which case the allocation would be leaked.
Separating the two implementations makes it much easier to read what the code is doing. PR libstdc++/85812 * libsupc++/cxxabi_init_exception.h (__cxa_free_exception): Declare. * libsupc++/exception_ptr.h (make_exception_ptr) [__cpp_exceptions]: Refactor to separate non-throwing and throwing implementations. [__cpp_rtti && !_GLIBCXX_HAVE_CDTOR_CALLABI]: Deallocate the memory if constructing the object throws. Tested powerpc64le-linux (and also using ASan to verify the fix). Committed to trunk. Backports to gcc-7 and gcc-8 will follow.
commit 3d02d84556f2be22945d397ed2fb4dbff8a0788e Author: Jonathan Wakely <jwak...@redhat.com> Date: Thu May 17 13:51:04 2018 +0100 PR libstdc++/85812 fix memory leak in std::make_exception_ptr PR libstdc++/85812 * libsupc++/cxxabi_init_exception.h (__cxa_free_exception): Declare. * libsupc++/exception_ptr.h (make_exception_ptr) [__cpp_exceptions]: Refactor to separate non-throwing and throwing implementations. [__cpp_rtti && !_GLIBCXX_HAVE_CDTOR_CALLABI]: Deallocate the memory if constructing the object throws. diff --git a/libstdc++-v3/libsupc++/cxxabi_init_exception.h b/libstdc++-v3/libsupc++/cxxabi_init_exception.h index d973a087f14..e438c1008d9 100644 --- a/libstdc++-v3/libsupc++/cxxabi_init_exception.h +++ b/libstdc++-v3/libsupc++/cxxabi_init_exception.h @@ -62,6 +62,9 @@ namespace __cxxabiv1 void* __cxa_allocate_exception(size_t) _GLIBCXX_NOTHROW; + void + __cxa_free_exception(void*) _GLIBCXX_NOTHROW; + // Initialize exception (this is a GNU extension) __cxa_refcounted_exception* __cxa_init_primary_exception(void *object, std::type_info *tinfo, diff --git a/libstdc++-v3/libsupc++/exception_ptr.h b/libstdc++-v3/libsupc++/exception_ptr.h index a927327214d..bd355ed880b 100644 --- a/libstdc++-v3/libsupc++/exception_ptr.h +++ b/libstdc++-v3/libsupc++/exception_ptr.h @@ -178,25 +178,31 @@ namespace std exception_ptr make_exception_ptr(_Ex __ex) _GLIBCXX_USE_NOEXCEPT { -#if __cpp_exceptions +#if __cpp_exceptions && __cpp_rtti && !_GLIBCXX_HAVE_CDTOR_CALLABI + void* __e = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ex)); + (void) __cxxabiv1::__cxa_init_primary_exception( + __e, const_cast<std::type_info*>(&typeid(__ex)), + __exception_ptr::__dest_thunk<_Ex>); try { -#if __cpp_rtti && !_GLIBCXX_HAVE_CDTOR_CALLABI - void *__e = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ex)); - (void)__cxxabiv1::__cxa_init_primary_exception( - __e, const_cast<std::type_info*>(&typeid(__ex)), - __exception_ptr::__dest_thunk<_Ex>); ::new (__e) _Ex(__ex); return exception_ptr(__e); -#else + } + catch(...) + { + __cxxabiv1::__cxa_free_exception(__e); + return current_exception(); + } +#elif __cpp_exceptions + try + { throw __ex; -#endif } catch(...) { return current_exception(); } -#else +#else // no RTTI and no exceptions return exception_ptr(); #endif }