A guest mmap with PROT_EXEC and MAP_SHARED of a shared-memory object or a regular file threw on Windows. The section is now created from a handle reopened with GENERIC_EXECUTE, as PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE, the owner ACE of named objects grants execute with read, and a writable shared mapping of a read-only descriptor fails with EACCES, as FreeBSD 11.4 shm_mmap and vn_mmap do.
Fixes#12337
sceKernelRmdir decided whether the last component was a symbolic link with
std::filesystem::is_symlink, which follows the link with WinLibs libstdc++ on
Windows. A dangling or self-referencing file link then looked missing on
Windows 10 (ENOENT instead of ENOTDIR), and a directory link to an empty
directory looked like that directory, so rmdir removed the link and
returned 0. The last component is now classified with FillLinkStat, the
same lstat path lstat_nid_postfix uses, matching FreeBSD 11 kern_rmdirat,
which returns ENOTDIR for any non-directory vnode found without following
the last link.
Fixes#12079
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This reverts commit 780b33aea3, restoring the 13824 MiB direct memory pool.
With the pool at 12288 MiB, Astro Bot (PPSA21564) can no longer load its
level: DirectMemoryAllocator asserts "Can't allocate direct memory" for a
64 MB VideoPlayerTexture with 12228 of 12288 MB in use, then the process
faults about 26 s in (2 of 2 runs, RTX 4090, Linux, main cccdaa2734).
The same tree with only this merge reverted runs the full 150 s with no
direct memory assert (2 of 2 runs).
scePthreadMutexattrSetkind called NotImplemented_nid_no_patch for a kind
outside 1 to 4. Firmware 13.42's libkernel, run in an emulator, makes it
call pthread_mutexattr_setkind_np, which stores any kind as a signed
16-bit value and returns 0, and turns a null attribute's -1 with errno 22
into 0x8001FFFF. It now forwards to pthread_mutexattr_setkind_np and
converts the result with sceKernelError, so a null attribute or object
still returns 0x8001FFFF and now also sets errno 22.
An out-of-range kind is refused by scePthreadMutexInit with 0x80020016,
leaving the mutex untouched, as measured for the same module.
scePthreadMutexattrGetkind is unchanged; kind 0 now reaches it and
returns 0.
sceKernelTruncate and truncate checked for a symbolic link loop only
after the native truncate failed, but on Windows std::filesystem::status
already reports a self-referencing link as missing, so the call returned
ENOENT before reaching that check. The loop check now runs before the
not-found result too.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
SuspendThread fails with STATUS_THREAD_IS_TERMINATING for a thread that
has begun to exit while its handle is not signaled yet. TryDeliver took
only the signaled handle as an exit, so the raise deliverer, which keeps
sweeping a target in host code until delivery or exit, threw "cannot
suspend the target thread" and aborted the process when that target
exited in between. The suspension now reads the NTSTATUS from
NtSuspendThread and treats a terminating target as exited; other
failures still throw.
guest_raise_exiting_thread raises at 32 threads per round that block in
a host wait and exit after it, for 100 rounds.
The test throws std::bad_alloc from a replaced operator new, so on MinGW it needs the same libc link, unwind section rename and DLL path as the other throwing guest tests (the Windows link failed on __gxx_personality_v0).
JsonObject held std::pair<std::string, JsonValue> while JsonValue was
still incomplete. Clang with libstdc++ instantiates the pair and the
vector destructor at the end of JsonValue and stops with "incomplete
type used in type trait expression". A named JsonMember struct defined
after JsonValue keeps the vector element a plain class.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Unbacked pages of a PRT range are anonymous zero pages, so a failed allocation puts those back with _zeroPrt instead of leaving the range reserved and unreadable.
_ammAllocatePrt took pool pages one at a time and mapped and recorded them run by run, so a failure on run k lost the pool pages of runs k to n. It now maps the unbacked part through AmmPool::MapScattered and returns the range to the reservation if that throws, and the unused _takePoolPages is gone.
Fail each allocation of a map from a fragmented pool, a map whose host call fails after each run, and a page insertion, and check that the pool and the page records are unchanged after every failure and that a map of one page more than the pool holds is still refused.
Move the pool bookkeeping into AmmPool.hpp. A map from a fragmented pool now plans its pages without changing the pool, stages the page and reference records in their own maps, maps the runs, and only then splits the pool and moves the records in with no allocation, so a failed map leaves the pool and the records as they were. Adding a page inserts its reference record first and undoes it if the page record throws.