mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
fix(libkernel): release only the main thread stack when moving it off the arena
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
3b1697cf1c
commit
11ca3cb744
2 files changed
+44
No files matched your search
@@ -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<std::uintptr_t>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "prx/libc/include/GuestArena.hpp"
|
||||
#include <crt_externs.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include <pthread.h>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
@@ -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<vm_region_recurse_info_t>(&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<std::uintptr_t>(&local);
|
||||
originalInArena = InArena(originalStack);
|
||||
originalArgument = argv[0];
|
||||
if (originalInArena) neighbour = MapStackNeighbour(originalStack);
|
||||
Aps5StartGuest_nid_no_patch(Guest, nullptr);
|
||||
}
|
||||
Reference in new issue
Block a user