Repository navigation
fix(libc): give the scripting heap hooks blocks from libc's own heap - #6842
Conversation
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
An independent bisect agrees. I bisected On current AI-assisted: yes |
|
Hollow Knight: Silksong (PPSA12544), another IL2CPP title that ships its own Linux, Ryzen 9 5950X, RTX 3080 Ti, NVIDIA 615.71.09, GCC 15.3, Release:
A AI-assisted: this comment was drafted with the help of Claude Code and checked against the logs by us. |
karimibrahim07
left a comment
There was a problem hiding this comment.
Windows check, since the description lists it as not checked. Head 35ea8317e merged onto main e3a8e4430 (clean merge). Windows 11 Pro (26300), Ryzen 5 3600, WinLibs GCC 15.2.0 r7, Ninja Release.
- All 9
application_heap_*tests pass,--repeat until-fail:3,application_heap_scriptingincluded. - Negative control: with
main'sApplicationHeap.cppand this PR's test,application_heap_scriptingandapplication_heap_replacementfail (0xc0000409), the same two tests as on Linux.
Overlap with #6713 (mine): the bot found a textual conflict in ApplicationHeap.cpp (tests) and docs/dev/debt/libc.md, because both PRs added a block right after the lazy case and a line under the scriptingGetMem entry. I moved #6713's test block and debt line away from yours (668d51a), so the two now merge cleanly in either order. With both merged onto main, all 10 application_heap_* tests pass 3 of 3. As you say, #6713 doesn't touch these two functions: it only changes ApplicationHeapInitialize for a null process-parameters pointer. With both applied, the hooks still never reach the registered allocator.
Code: routing the hooks to GuestHeap instead of ApplicationHeapAlign makes sense given the MGS4 and Silksong results: those titles' own libc owns the registered allocator, and the hooks were initializing it a second time. Catching std::length_error alongside bad_alloc matches the new SIZE_MAX check. I have no code requests.
Not checked here: a title. I don't have MGS4, Silksong or a Unity title that uses AnyPS5's own libc (the PPSA28997 case you mention). For that case the GC's blocks now come from libc's heap instead of the title's allocator, so a run of it would be the useful remaining evidence.
AI-assisted: yes. I ran the build, the tests and the negative control above.
|
Thanks @karimibrahim07 for the Windows run and the negative control, and for moving #6713's block so the two merge in either order. I added it to the description. AI-assisted: yes (Claude Code) |
|
Confirmed on PPSA28997 (God of War: Sons of Sparta), Linux, RADV (Ryzen Z2 Go / REMBRANDT, Mesa 26.2.0-devel), main e09dbc2. PPSA28997 ships its own
|
|
Thanks @utajum, that's a useful run. It's a third IL2CPP title with its own AI-assisted: yes (Claude Code) |
35ea831 to
38b2217
Compare
scriptingGetMem and scriptingFreeMem went through the title's registered allocator. A title that ships its own libc.prx has already initialized that allocator, and the application heap's lazy initialization then ran its initializer a second time: Metal Gear Solid Master Collection (PPSA18194) started a second Unity heap and aborted when it freed a block of the first. The hooks now allocate and free through libc's guest heap, so they never initialize the registered allocator; sizes that overflow return null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
38b2217 to
b4e129f
Compare
|
Checked on macOS: Apple M4 Pro, macOS 27.0.1 (26A434), Rosetta 2, Apple clang 21.0.0, Vulkan SDK 1.4.363.0 (MoltenVK 1.4.2).
Not checked: other titles on macOS. AI-assisted: yes (Claude Code). I ran all of the above on my machine. |
…ocks from libc's own heap (@milescoviello) Brings the open upstream fix for the IL2CPP scripting heap hooks: without it God of War: Sons of Sparta (PPSA28997) ends with SIGSEGV at start-up through the IL2CPP free and abort chain, as imellag traced on boykopovar#7332, where boykopovar#6842 merged cleanly and its tests and the title check passed on macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ocks from libc's own heap (@milescoviello) Includes the open upstream fix for the IL2CPP scripting heap hooks, which God of War: Sons of Sparta needs on macOS to get past start-up, as on the fork's main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @imellag for the macOS run and the Sons of Sparta check. I added it to the description. AI-assisted: yes (Claude Code) |
|
Checked the two hooks against |
main's new conventions check (fb1ad2f) warns about a debt entry this branch adds or changes when it runs over 1000 characters, and two of the branch's entries linked no core path, which the check refuses. The macOS paragraphs this branch had appended to main's entries (provoking vertex, sceKernelGetModuleInfoFromAddr, JIT shared memory, getrlimit, socketpair) now stand as their own entries under the same links, and main's entries are back as main has them. The branch's own entries (the scripting heap hooks from boykopovar#6842, the loopback connect retry, macOS guest TLS, the barycentric built-ins) are rewritten to state the gap first within the limit. The attachment-less multisample note links Pipeline.cpp, and boykopovar#7173's ADCX/ADOX note links the lowering, so each sits in the file its link names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Also fixes Plants vs. Zombies™: Replanted (PPSA29802, #6404): on Linux 47a266c it aborted in the title's |
|
@madkyp thanks for the report. Good to know Plants vs. Zombies: Replanted (PPSA29802) had the same cross-heap AI-assisted: yes (Claude Code) |
What
Since #5092 (merged 10-15), Metal Gear Solid Master Collection (PPSA18194) dies 0 s in on
main:EXIT-139with no message, 5 of 5 runs on 82ddae7 (one of them with #6814 applied). Before #5092 its Unity launcher ran. In the 10-15 sweep (0029e62) it reached itsLoadExecintomgs4/mgs4.elfat 30 s, a 30 s run on that build reaches the limit, and with #5092 reverted on 82ddae7 it reaches the limit 2 of 2.What happens:
libc.prx. At start, that libc initializes the title's malloc replacement, and Unity puts its heap in a 256 MiB direct mapping at0x200000000.scriptingGetMemby name (the only hook name inIl2cppUserAssemblies.prx) and now finds feat(libc): provide the runtime scripting allocator hooks #5092's hook. The hook allocates throughApplicationHeapAlign. That heap is not initialized in this process (_init_envbelongs to the title's own libc), so the lazy initialization from feat(libc): lazily initialize application heap on first access #4774 reads the same replacement table from the process parameters and calls its initialize callback a second time.APS5_TRACE_MEMORY=1, a new 256 MiB mapping at0x215000000appears right before the fourscriptingGetMem(0x1000, 0x40000)calls. The run with feat(libc): provide the runtime scripting allocator hooks #5092 reverted makes no such mapping.freeof a block from the first heap fails dlmalloc'sleast_addrcheck (the core hasmspace_free(0x215000010, 0x200001060)). The player then calls the title libc'sabort(int 0x45), which ends the process with SIGSEGV.How
The two hooks now allocate and free through libc's own guest heap (
GuestHeapAlign/GuestHeapFree) instead of the title's registered allocator, so calling them never initializes that allocator. The alignment rules stay as #5092 made them. A size that overflows now returns null instead of throwing. The debt entry records why, and that which console library exports the hooks is still unknown.Tested
Ubuntu 24.04, GCC 13.3, Release, RTX 4070 Ti (NVIDIA 595.99).
application_heap_scripting: with the process parameters installed and the heap not yet initialized, twoscriptingGetMem(0x1000, 0x40000)blocks are 4 KiB-aligned, distinct and writable. Neither they nor their frees reach the registered allocator, and_init_envafterwards initializes it exactly once.main'sApplicationHeap.cpp,application_heap_scriptingandapplication_heap_replacementfail. With the change, all 9application_heap_*tests pass 3 of 3, and the 396 tests matchingapplication_heap|guest_|libc|getifaddrs|heappass.EXIT-139at 0 s. With this PR, 3 of 3 30 s runs reach the limit with the same log as the 10-15 build (542–553 lines, the same textures and asset bundles), and a 120 s run stops where the 10-15 sweep did: at 30 s, onsceWebBrowserDialogOpenForPredeterminedContent not implemented(open feat(libSceWebBrowserDialog): implement sceWebBrowserDialogOpenForPredeterminedContent #5904 and feat(libSceWebBrowserDialog): finish PredeterminedContent without UI (PPSA34015) #6092).scriptingGetMemvariantEXIT-1390 sEXIT-1390 sEXIT-1390 sscriptingFreeMemSo the contents and bounds of the blocks don't matter; reaching the title's allocator does.
@mrfelek found the same crash in Hollow Knight: Silksong (PPSA12544), another IL2CPP title with its own
libc.prx. Onmainaf7db81 it segfaults about 30 s in. With #5092 reverted, or with this PR (35ea8317e), it runs at about 1,050–1,200 presents per 10 s. Theirgit bisect --first-parentalso lands on #5092's merge.@karimibrahim07 checked it on Windows (Windows 11, WinLibs GCC 15.2.0, Release). All 9
application_heap_*tests pass 3 of 3. Withmain'sApplicationHeap.cpp,application_heap_scriptingandapplication_heap_replacementfail, the same two as on Linux.@utajum confirmed it on God of War: Sons of Sparta (PPSA28997) on Linux with RADV (Ryzen Z2 Go, Mesa 26.2.0-devel), on
maine09dbc2. That title ships its ownlibc.prx, so it is this PR's case, not #694's. Onmainit segfaults at start-up right afterglobal-metadata.datopens, in the sameil2cpp_init→ titlefree→ titleabortchain as MGS4. With this PR'sApplicationHeap.cppit boots, loads a save and plays, in 10 runs of 75–180 s with no crash.@imellag checked it on macOS (Apple M4 Pro, Rosetta 2, MoltenVK 1.4.2), with this head merged into #7332, which adds the macOS runtime. The 9
application_heap_*tests pass, and with the earlierApplicationHeap.cppthe same two abort. God of War: Sons of Sparta segfaults about a second afterglobal-metadata.datopens without this PR, in the same chain, and with it the game reaches gameplay.Not checked: a Unity title that runs on AnyPS5's libc, whose GC now gets its blocks from libc's heap instead of the title's allocator.
#6713 edits the same files for executables without process parameters; it does not touch these functions. @karimibrahim07 moved #6713's test block and debt line (668d51a), so the two merge cleanly in either order.
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code