Files
AnyPS5/core/libs/tests/UndeliverableHostException.cpp
T
Yunus Shaikh da6948ea18 fix(libc): report host C++ exceptions that Windows cannot deliver
libstdc++ and libgcc raise C++ exceptions as SEH exceptions
(STATUS_GCC_THROW, 0x20474343), which the system dispatcher delivers by
unwinding frame by frame with each function's unwind data. The libraries
are built with -fno-asynchronous-unwind-tables and unwind with DWARF, so
their functions have no SEH unwind data. When a host runtime call such as
operator new throws straight into one of them, the dispatcher cannot
unwind it: no handler, the unhandled exception filter or std::terminate
runs, and the process ends without output and with exit code 0x20474343.

The vectored crash handler now follows a GCC exception through the
runtime frames that raise it (KERNELBASE, libgcc_s_seh-1, libstdc++-6).
When the first frame outside them has no unwind data, it reports the
exception's type, the thread and that frame, and lists the stack's
return address candidates, before the dispatcher continues.

The test loads libc.prx, then lets operator new throw std::bad_alloc
into a function built with the libraries' flags. Without the handler
change it exits silently with 0x20474343.
2026-10-12 11:25:20 -07:00

30 lines
867 B
C++

#include <cstddef>
#include <cstdio>
#include <new>
#include <windows.h>
namespace {
[[gnu::noinline]] void* AllocateWithoutUnwindData(std::size_t size) {
void* const block = ::operator new(size);
std::printf("allocated %p\n", block);
return block;
}
}
int main(int argc, char** argv) {
if (argc != 2) {
std::fprintf(stderr, "usage: %s <libc.prx>\n", argv[0]);
return 2;
}
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
if (LoadLibraryExA(argv[1], nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) == nullptr) {
std::fprintf(stderr, "%s: LoadLibraryEx failed with error %lu\n", argv[1], GetLastError());
return 1;
}
AllocateWithoutUnwindData(std::size_t{1} << 46);
std::fputs("operator new returned instead of throwing\n", stderr);
return 1;
}