diff --git a/core/libs/prx/libkernel/Pthread/src/MainThreadMacOs.cpp b/core/libs/prx/libkernel/Pthread/src/MainThreadMacOs.cpp index 1b6e6d976a..a86e2fbcba 100644 --- a/core/libs/prx/libkernel/Pthread/src/MainThreadMacOs.cpp +++ b/core/libs/prx/libkernel/Pthread/src/MainThreadMacOs.cpp @@ -91,6 +91,12 @@ HostStack FindHostStack() { if (!RegionOf(stack.low - 1, begin, end, tag) || tag != VM_MEMORY_STACK || end != stack.low) break; stack.low = begin; } + const pthread_t self = pthread_self(); + const auto top = reinterpret_cast(pthread_get_stackaddr_np(self)); + const std::uintptr_t size = pthread_get_stacksize_np(self); + stack.low = std::max(stack.low, top - std::min(top, size)); + stack.high = std::min(stack.high, top); + if (stack.low >= stack.high) return {}; return stack; } diff --git a/core/libs/tests/GuestMainStackMove.cpp b/core/libs/tests/GuestMainStackMove.cpp index a177574f9c..1030bb792a 100644 --- a/core/libs/tests/GuestMainStackMove.cpp +++ b/core/libs/tests/GuestMainStackMove.cpp @@ -1,5 +1,7 @@ #include "prx/libc/include/GuestArena.hpp" #include +#include +#include #include #include #include @@ -14,10 +16,40 @@ namespace { constexpr std::uintptr_t MappingAlignment = 0x10000; constexpr std::size_t MappingBytes = 0x10000; +constexpr std::size_t NeighbourBytes = std::size_t {1} << 20; std::uintptr_t originalStack = 0; std::string originalArgument; bool originalInArena = false; +mach_vm_address_t neighbour = 0; + +bool RegionOf(mach_vm_address_t address, mach_vm_address_t& begin, mach_vm_address_t& end, std::uint32_t& tag) { + mach_vm_address_t base = address; + mach_vm_size_t size = 0; + natural_t depth = 0; + vm_region_submap_info_data_64_t info {}; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + if (mach_vm_region_recurse(mach_task_self(), &base, &size, &depth, reinterpret_cast(&info), &count) != KERN_SUCCESS || base > address) return false; + begin = base; + end = base + size; + tag = info.user_tag; + return true; +} + +mach_vm_address_t MapStackNeighbour(std::uintptr_t stack) { + mach_vm_address_t low = 0, end = 0; + std::uint32_t tag = 0; + if (!RegionOf(stack, low, end, tag) || tag != VM_MEMORY_STACK) return 0; + for (;;) { + mach_vm_address_t begin = 0, previousEnd = 0; + if (!RegionOf(low - 1, begin, previousEnd, tag) || tag != VM_MEMORY_STACK || previousEnd != low) break; + low = begin; + } + mach_vm_address_t at = low - NeighbourBytes; + if (mach_vm_deallocate(mach_task_self(), at, NeighbourBytes) != KERN_SUCCESS) return 0; + if (mach_vm_allocate(mach_task_self(), &at, NeighbourBytes, VM_MAKE_TAG(VM_MEMORY_STACK)) != KERN_SUCCESS) return 0; + return at; +} void Require(bool value, const char* what) { if (value) return; @@ -47,6 +79,11 @@ void CheckMainThread(void*) { } GuestArena::GuestArenaRelease_nid_postfix(old, MappingBytes); } + if (neighbour != 0) { + mach_vm_address_t begin = 0, end = 0; + std::uint32_t tag = 0; + Require(RegionOf(neighbour, begin, end, tag) && tag == VM_MEMORY_STACK, "a stack region next to the main stack survived the move"); + } Require(originalArgument == (*_NSGetArgv())[0], "argv survived the move"); Require(std::getenv("PATH") != nullptr, "the environment survived the move"); } @@ -63,5 +100,6 @@ int main(int, char** argv) { originalStack = reinterpret_cast(&local); originalInArena = InArena(originalStack); originalArgument = argv[0]; + if (originalInArena) neighbour = MapStackNeighbour(originalStack); Aps5StartGuest_nid_no_patch(Guest, nullptr); }