Files
AnyPS5/core/libs/tests/HostLibstdcxxExceptionModule.cpp
T
fma-rc c020d73a5b fix(libc): catch exceptions that libstdc++ throws inside the prx libraries on Linux
The nid_patcher turns each *_nid_no_patch_cut alias into a second dynamic
symbol with the same name as the plain alias exported next to it, seven
names in all. With those duplicates, LD_DEBUG=bindings shows libstdc++ keeping its own __cxa_allocate_exception, __cxa_throw,
__cxa_begin_catch, __cxa_end_catch, __cxa_rethrow, __gxx_personality_v0
and _Unwind_Resume while taking __cxa_init_primary_exception,
_Unwind_RaiseException and std::terminate from libc.prx. An exception
thrown inside libstdc++ (std::stoi, a stream with exceptions enabled) got
a libc header laid over a libstdc++ allocation, reached the libc
personality as a foreign exception, matched no typed handler and ended in
"terminate called without an active exception". The plain aliases already
export these names, so the duplicates go.

libstdc++ also describes std::__ios_failure with __iosfail_type_info, a
class that privately derives from __si_class_type_info at the same
address. Kind now follows such single same-address bases to the
__cxxabiv1 class, so catching std::ios_base::failure or std::exception
matches a stream failure.

The plain aliases came in a4c519b26 next to the cut aliases from
14f8c16ac.
2026-10-17 01:17:45 +02:00

63 lines
1.8 KiB
C++

#include <exception>
#include <fstream>
#include <ios>
#include <stdexcept>
#include <string>
static bool CatchesConversion() {
try {
(void)std::stoi("x");
} catch (const std::invalid_argument& error) {
return std::string(error.what()) == "stoi";
}
return false;
}
static bool CatchesStreamFailure(const char* path) {
try {
std::ofstream file;
file.exceptions(std::ios::failbit);
file.open(path);
} catch (const std::ios_base::failure&) {
return true;
}
return false;
}
static bool CatchesStreamFailureAsException(const char* path) {
try {
std::ofstream file;
file.exceptions(std::ios::failbit);
file.open(path);
} catch (const std::exception&) {
return true;
}
return false;
}
static bool RethrowsStoredStreamFailure(const char* path) {
std::exception_ptr failure;
try {
std::ofstream file;
file.exceptions(std::ios::failbit);
file.open(path);
} catch (...) {
failure = std::current_exception();
}
if (!failure) return false;
try {
std::rethrow_exception(failure);
} catch (const std::ios_base::failure&) {
return true;
}
return false;
}
extern "C" const char* HostLibstdcxxExceptionFailure(const char* path) {
if (!CatchesConversion()) return "std::stoi failure was not caught as std::invalid_argument";
if (!CatchesStreamFailure(path)) return "std::ofstream::open failure was not caught as std::ios_base::failure";
if (!CatchesStreamFailureAsException(path)) return "std::ofstream::open failure was not caught as std::exception";
if (!RethrowsStoredStreamFailure(path)) return "a stored std::ofstream::open failure was not rethrown";
return nullptr;
}