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:
commit
c101c91bbb
|
|
@ -109,6 +109,16 @@ asm(".text\n"
|
||||||
" popq %rsi\n"
|
" popq %rsi\n"
|
||||||
" popq %rdi\n"
|
" popq %rdi\n"
|
||||||
"2:\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"
|
" movq %rdi, %rdx\n"
|
||||||
" movl %esi, %eax\n"
|
" movl %esi, %eax\n"
|
||||||
" movq 0(%rdx), %rcx\n"
|
" movq 0(%rdx), %rcx\n"
|
||||||
|
|
|
||||||
|
|
@ -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, ...);
|
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);
|
[[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);
|
[[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 sigprocmask_nid_postfix(int how, const void* set, void* previousSet);
|
||||||
int* APS5_VABI __error_nid_postfix();
|
int* APS5_VABI __error_nid_postfix();
|
||||||
|
|
||||||
|
|
@ -150,6 +152,7 @@ int g_entries = 0;
|
||||||
Fibre g_dispatcher = {};
|
Fibre g_dispatcher = {};
|
||||||
Fibre g_job = {};
|
Fibre g_job = {};
|
||||||
int g_jobRuns = 0;
|
int g_jobRuns = 0;
|
||||||
|
bool g_signalJumps = false;
|
||||||
|
|
||||||
void Require(bool value, const char* what) {
|
void Require(bool value, const char* what) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
|
|
@ -348,6 +351,14 @@ namespace {
|
||||||
|
|
||||||
[[gnu::noinline]] void Switch(Fibre* from, Fibre* to) {
|
[[gnu::noinline]] void Switch(Fibre* from, Fibre* to) {
|
||||||
from->started = 1;
|
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 (setjmp_nid_postfix(from->jump) == 0) {
|
||||||
if (to->started) longjmp_nid_postfix(to->jump, 1);
|
if (to->started) longjmp_nid_postfix(to->jump, 1);
|
||||||
setcontext_nid_postfix(&to->context);
|
setcontext_nid_postfix(&to->context);
|
||||||
|
|
@ -360,7 +371,7 @@ namespace {
|
||||||
extern "C" void APS5_VABI JobEntry() {
|
extern "C" void APS5_VABI JobEntry() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
++g_jobRuns;
|
++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();
|
ThrowAndCatch();
|
||||||
Switch(&g_job, &g_dispatcher);
|
Switch(&g_job, &g_dispatcher);
|
||||||
}
|
}
|
||||||
|
|
@ -402,7 +413,11 @@ void CheckMakecontext() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckJumpBuffers() {
|
void CheckJumpBuffers(bool signalJumps) {
|
||||||
|
g_signalJumps = signalJumps;
|
||||||
|
g_jobRuns = 0;
|
||||||
|
g_dispatcher = {};
|
||||||
|
g_job = {};
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ULONG_PTR threadLow = 0;
|
ULONG_PTR threadLow = 0;
|
||||||
ULONG_PTR threadHigh = 0;
|
ULONG_PTR threadHigh = 0;
|
||||||
|
|
@ -420,7 +435,7 @@ void CheckJumpBuffers() {
|
||||||
ULONG_PTR low = 0;
|
ULONG_PTR low = 0;
|
||||||
ULONG_PTR high = 0;
|
ULONG_PTR high = 0;
|
||||||
GetCurrentThreadStackLimits(&low, &high);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -466,7 +481,8 @@ int main(int argc, char** argv) {
|
||||||
CheckSignalMask();
|
CheckSignalMask();
|
||||||
std::thread([] {
|
std::thread([] {
|
||||||
CheckMakecontext();
|
CheckMakecontext();
|
||||||
CheckJumpBuffers();
|
CheckJumpBuffers(false);
|
||||||
|
CheckJumpBuffers(true);
|
||||||
GrowStack(32);
|
GrowStack(32);
|
||||||
}).join();
|
}).join();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue