test(libc): pinned shared pages stay writable and are collected as written
Also unpin the previous context when a fiber object is initialised again without being finalised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
57588cf2dd
commit
78cb1598ce
|
|
@ -330,6 +330,7 @@ int32_t APS5_VABI _sceFiberInitializeImpl_nid_postfix(FiberObject* object, const
|
|||
if (addr_context == nullptr) return SCE_FIBER_ERROR_INVALID;
|
||||
if (size_context < FIBER_MIN_CONTEXT_SIZE) return SCE_FIBER_ERROR_RANGE;
|
||||
auto* fiber = reinterpret_cast<Fiber*>(object);
|
||||
if (fiber->magic == FIBER_MAGIC) UnpinStack(fiber->context, fiber->contextSize);
|
||||
std::memset(object, 0, FIBER_OBJECT_SIZE);
|
||||
fiber->magic = FIBER_MAGIC;
|
||||
fiber->state.store(FiberState::Idle, std::memory_order_relaxed);
|
||||
|
|
|
|||
|
|
@ -672,6 +672,49 @@ static void CheckSharedWriteTracking() {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void CheckPinnedSharedPages() {
|
||||
#ifdef _WIN32
|
||||
constexpr std::size_t page = 0x4000;
|
||||
std::int64_t phys = 0;
|
||||
Require(sceKernelAllocateDirectMemory(0, 0x7fffffffffll, page * 3, 0, 0, &phys) == 0);
|
||||
void* mapped = nullptr;
|
||||
Require(sceKernelMapDirectMemory(&mapped, page * 3, 3, 0, phys, 0) == 0);
|
||||
auto* bytes = static_cast<volatile unsigned char*>(mapped);
|
||||
const auto collect = [&] {
|
||||
std::array<void*, 32> pages{};
|
||||
std::size_t count = pages.size();
|
||||
Require(GuestArena::GuestArenaCollectWrites_nid_postfix(reinterpret_cast<std::uintptr_t>(mapped), page * 3, pages.data(), &count, true));
|
||||
return count;
|
||||
};
|
||||
const auto protection = [&](std::size_t offset) {
|
||||
MEMORY_BASIC_INFORMATION info{};
|
||||
Require(VirtualQuery(const_cast<unsigned char*>(bytes + offset), &info, sizeof(info)) == sizeof(info));
|
||||
return info.Protect;
|
||||
};
|
||||
collect();
|
||||
Require(collect() == 0);
|
||||
Require(protection(0) == PAGE_READONLY && protection(page) == PAGE_READONLY);
|
||||
GuestArena::GuestArenaPinWritable_nid_postfix(const_cast<unsigned char*>(bytes + page), page);
|
||||
Require(protection(page) == PAGE_READWRITE && protection(0) == PAGE_READONLY && protection(page * 2) == PAGE_READONLY);
|
||||
Require(collect() == 4);
|
||||
Require(collect() == 4);
|
||||
Require(protection(page) == PAGE_READWRITE);
|
||||
bytes[page + 8] = 7;
|
||||
bytes[0] = 9;
|
||||
Require(collect() == 8);
|
||||
Require(collect() == 4);
|
||||
Require(protection(0) == PAGE_READONLY && protection(page) == PAGE_READWRITE);
|
||||
GuestArena::GuestArenaUnpinWritable_nid_postfix(const_cast<unsigned char*>(bytes + page), page);
|
||||
collect();
|
||||
Require(collect() == 0);
|
||||
Require(protection(page) == PAGE_READONLY);
|
||||
bytes[page + 8] = 11;
|
||||
Require(collect() == 4);
|
||||
Require(sceKernelMunmap(mapped, page * 3) == 0);
|
||||
Require(sceKernelReleaseDirectMemory(phys, page * 3) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void CheckReadsIntoSharedWriteTracking() {
|
||||
#ifdef _WIN32
|
||||
constexpr std::size_t page = 0x4000;
|
||||
|
|
@ -937,6 +980,7 @@ int main() {
|
|||
#endif
|
||||
CheckSharedWriteTracking();
|
||||
CheckReadsIntoSharedWriteTracking();
|
||||
CheckPinnedSharedPages();
|
||||
#if defined(__linux__)
|
||||
CheckWriteWatch();
|
||||
CheckDirectMemoryWriteWatch();
|
||||
|
|
|
|||
Loading…
Reference in New Issue