Merge pull request #5272 from milescoviello/carry/siglongjmp-stack-windows-5270

fix(libkernel): switch the host stack bounds in siglongjmp on Windows
This commit is contained in:
Dean 2026-10-14 14:24:40 +13:00 committed by GitHub
commit c101c91bbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 30 additions and 4 deletions

View File

@ -109,6 +109,16 @@ asm(".text\n"
" popq %rsi\n"
" popq %rdi\n"
"2:\n"
#ifdef _WIN32
" pushq %rdi\n"
" pushq %rsi\n"
" movq 16(%rdi), %rdi\n"
" subq $8, %rsp\n"
" call GuestStackSwitch_nid_no_patch\n"
" addq $8, %rsp\n"
" popq %rsi\n"
" popq %rdi\n"
#endif
" movq %rdi, %rdx\n"
" movl %esi, %eax\n"
" movq 0(%rdx), %rcx\n"

View File

@ -21,6 +21,8 @@ int APS5_VABI setcontext_nid_postfix(const UserUcontext* context);
void APS5_VABI makecontext_nid_postfix(UserUcontext* context, ContextEntry entry, int count, ...);
[[gnu::returns_twice]] int APS5_VABI setjmp_nid_postfix(std::uint64_t* buffer);
[[noreturn]] void APS5_VABI longjmp_nid_postfix(std::uint64_t* buffer, int value);
[[gnu::returns_twice]] int APS5_VABI sigsetjmp_nid_postfix(std::uint64_t* buffer, int saveMask);
[[noreturn]] void APS5_VABI siglongjmp_nid_postfix(std::uint64_t* buffer, int value);
int APS5_VABI sigprocmask_nid_postfix(int how, const void* set, void* previousSet);
int* APS5_VABI __error_nid_postfix();
@ -150,6 +152,7 @@ int g_entries = 0;
Fibre g_dispatcher = {};
Fibre g_job = {};
int g_jobRuns = 0;
bool g_signalJumps = false;
void Require(bool value, const char* what) {
if (!value) {
@ -348,6 +351,14 @@ namespace {
[[gnu::noinline]] void Switch(Fibre* from, Fibre* to) {
from->started = 1;
if (g_signalJumps) {
if (sigsetjmp_nid_postfix(from->jump, 1) == 0) {
if (to->started) siglongjmp_nid_postfix(to->jump, 1);
setcontext_nid_postfix(&to->context);
Require(false, "setcontext into the job returned");
}
return;
}
if (setjmp_nid_postfix(from->jump) == 0) {
if (to->started) longjmp_nid_postfix(to->jump, 1);
setcontext_nid_postfix(&to->context);
@ -360,7 +371,7 @@ namespace {
extern "C" void APS5_VABI JobEntry() {
for (;;) {
++g_jobRuns;
CheckStackBounds(&g_jobStack, "the stack bounds follow longjmp onto the job stack");
CheckStackBounds(&g_jobStack, g_signalJumps ? "the stack bounds follow siglongjmp onto the job stack" : "the stack bounds follow longjmp onto the job stack");
ThrowAndCatch();
Switch(&g_job, &g_dispatcher);
}
@ -402,7 +413,11 @@ void CheckMakecontext() {
#endif
}
void CheckJumpBuffers() {
void CheckJumpBuffers(bool signalJumps) {
g_signalJumps = signalJumps;
g_jobRuns = 0;
g_dispatcher = {};
g_job = {};
#ifdef _WIN32
ULONG_PTR threadLow = 0;
ULONG_PTR threadHigh = 0;
@ -420,7 +435,7 @@ void CheckJumpBuffers() {
ULONG_PTR low = 0;
ULONG_PTR high = 0;
GetCurrentThreadStackLimits(&low, &high);
Require(low == threadLow && high == threadHigh, "the stack bounds follow longjmp back to the thread stack");
Require(low == threadLow && high == threadHigh, signalJumps ? "the stack bounds follow siglongjmp back to the thread stack" : "the stack bounds follow longjmp back to the thread stack");
#endif
}
}
@ -466,7 +481,8 @@ int main(int argc, char** argv) {
CheckSignalMask();
std::thread([] {
CheckMakecontext();
CheckJumpBuffers();
CheckJumpBuffers(false);
CheckJumpBuffers(true);
GrowStack(32);
}).join();
return 0;