Repository navigation
fix(libc): call guest unwind callbacks with the System V ABI on Windows - #6851
Conversation
_Unwind_Backtrace and _Unwind_ForcedUnwind call the trace and stop functions a title passes them, and _Unwind_DeleteException calls the exception_cleanup of the exception it deletes. Their types in UnwindAbi.hpp had no APS5_VABI, so on Windows these guest functions were called with the Microsoft x64 convention: the context and the argument went to rcx and rdx while the guest reads rdi and rsi. vkQuake (PPSA99010) imports _Unwind_Backtrace and reads each frame in its callback (db3ec02). The three types are now APS5_VABI, like the callbacks of __cxa_vec_ctor and the other libc exports, and so is Cleanup, the exception_cleanup of the exceptions libc throws. An exception thrown by libstdc++ on Windows (class GNUCC++) has a host cleanup, so _Unwind_DeleteException passes it to libgcc's _Unwind_DeleteException, which calls that cleanup as before. Linux and macOS are unchanged.
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
Title run on Windows with vkQuake (PPSA99010, catalog release 1.0) and the free Quake shareware data, so the crash this PR describes can be reproduced without anyone's own game files. Windows 11 Pro build 26300, Intel i7-11700F, NVIDIA GeForce RTX 3070, WinLibs GCC 15.2, Release, relinked with (
What the crash is, from the disassembly of the relinked Controller-only runs (the fixed pad sequence, 150 s): on AI-assisted: yes |
|
@DavidSamir thank you, that is the reproduction this PR needed: a public title with free data, where |
|
Checked the diff against the description: the three callback types and |
What
On Windows, AnyPS5 called three kinds of guest callbacks with the Microsoft x64 convention instead of System V:
_Unwind_Backtrace,_Unwind_ForcedUnwind,exception_cleanupof an exception deleted by_Unwind_DeleteException, including the foreign exceptions that__cxa_end_catchdeletes.Their types in
UnwindAbi.hpp(_Unwind_Trace_Fn,_Unwind_Stop_Fnand_Unwind_Exception::exception_cleanup) had noAPS5_VABI. Sotrace(&context, argument)inUnwind.cppput the context and the argument inrcxandrdx, while the guest function readsrdiandrsi; the stop function and the cleanup got wrong arguments the same way. The relinker passes guest function pointers to libc unchanged, and the other guest callbacks in libc already haveAPS5_VABI, e.g. the constructor and destructor of__cxa_vec_ctor_nid_postfix. vkQuake (PPSA99010) imports_Unwind_Backtraceand reads each frame in its callback (db3ec02), so on Windows its callback got a wrong context.Changes:
APS5_VABI.Cleanup, theexception_cleanupof the exceptions libc throws, has it too. With the new types the compiler rejects any other host function stored in them on Windows, andCleanupwas the only one._Unwind_DeleteExceptionalso deletes exceptions thrown insidelibstdc++-6.dllwhen code that takes__cxa_begin_catchand__cxa_end_catchfromlibc.prxcatches them. Their class isGNUCC++and their cleanup is a host function, so_Unwind_DeleteException_nid_postfixpasses them to libgcc's_Unwind_DeleteException, which calls the cleanup as before. With every cleanup called as System V, a small program built with SEH unwind tables that catchesstd::stoi("x")crashed in__gxx_exception_cleanup; with this change it catches the exception 3 of 3 times, as onmain. The AnyPS5 modules themselves are built with-fno-asynchronous-unwind-tables, so they cannot catch such an exception, onmaineither:windows_exception_testsreports the samestd::stoiexception as undeliverable.-O3inlines_Unwind_DeleteException_nid_postfixinto__cxa_end_catch_nid_postfixand merges the two indirect calls, which differ only in their calling convention, into the System V one (-fno-tree-tail-mergekeeps both). The call to libgcc is a direct call, so it cannot be merged.APS5_VABIis empty there.New test
core/libs/tests/UnwindCallbackAbi.cpp, registered on every platform as five ctest tests. Each passes callbacks declaredAPS5_VABIlike a guest does:unwind_callback_abi_backtrace: the trace function gets the argument given to_Unwind_Backtraceand a context whose region start is the function that called_Unwind_Backtrace.unwind_callback_abi_forced_unwind: the stop function gets version 1,_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND, the exception class, the exception, the argument given to_Unwind_ForcedUnwindand the context of its caller.unwind_callback_abi_delete_exception:_Unwind_DeleteExceptioncallsexception_cleanuponce with_URC_FOREIGN_EXCEPTION_CAUGHTand the exception.unwind_callback_abi_end_catch: the same after__cxa_begin_catchand__cxa_end_catchon a foreign exception.unwind_callback_abi_end_catch_gnu: the same with aGNUCC++exception whose cleanup is a host function.ExceptionRuntime.cppstill passes host lambdas as these types. It is built only on Linux and macOS, where the types are unchanged.My open PR #6819 adds an
unwind_cursortest whoseTraceFirstFrameis a host function passed to_Unwind_Backtrace_nid_postfix. The two branches merge without conflicts, but once both are in, that test no longer compiles on Windows untilTraceFirstFrameis markedAPS5_VABI. I'll add that to whichever of the two is merged second.Tested
Windows 10 Pro 22H2 (19045), MinGW-w64 GCC 15.2.0 (WinLibs r7), Ninja, Release,
BUILD_TESTING=ON, onmain82ddae75b. The new test binary was run 20 times per test against three builds oflibc.prx:mainbacktracethe trace callback gets the argument given to _Unwind_Backtraceforced_unwindthe stop function gets version 1delete_exceptionexception_cleanup gets _URC_FOREIGN_EXCEPTION_CAUGHTend_catchexception_cleanup gets _URC_FOREIGN_EXCEPTION_CAUGHTend_catch_gnuexception_cleanup gets _URC_FOREIGN_EXCEPTION_CAUGHTctest -R "exception|unwind|backtrace|personality|terminate|signal"pass, includingwindows_exceptions,windows_backtrace_*,guest_exception_*,guest_raise_exception,guest_unwind_module_info,guest_mutex_raise_exception,unwind_record_bounds,undeliverable_host_exceptionandguest_signal*.ctest -j 12: 1324 of 1326 pass.agc_shader_disk_cachefails withAccess is deniedas onmainon Windows 10 (test(agc): delete mapped shader cache entries with POSIX semantics on Windows #6415), andagc_driver_gpu_indirect_arguments_misaligned_writer_ahead_testsdoes not build with MinGW onmain(alignment 65536 above the object file maximum of 8192, test(agc): align the indirect arguments block at run time #6452).python tools/check_conventions.py --base origin/mainpasses.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)