You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cult of the Lamb (PPSA06465) on Windows: intermittent fault in Loading.PreloadManager during start-up (about half of 40 s runs) #5490
Cult of the Lamb (PPSA06465, Unity IL2CPP, my own dump), Windows 11, MinGW-w64 GCC 15 (winlibs), Release. Relinked from a fresh work directory with --windows --module-dir Media/Modules --module-dir Media/Plugins. It intermittently faults on thread Loading.PreloadManager during start-up, 10 to 20 s in.
How often (40 s runs; the libraries changed between runs, the relinked app.exe and work directory didn't):
5 of 8 (one of them FATAL: UCRT invalid parameter instead)
An older main41b0ca597 with about 15 open PRs merged
4 of 4
Other short series on main gave 1 of 6 and 3 of 4. The runs that don't fault keep going: shaders compile, frames are presented, and the music bank opens. Runs with --trace-imports and APS5_TRACE_CALLS=all didn't fault in 2 runs, which fits a timing-dependent race.
The fault site changes from run to run, always on Loading.PreloadManager while asset files are being opened:
rip libc.prx.guest.prx+0x20796, the title's own libc.prx at ELF 0x10796. This is the guest libc's memcpy-style bounds check: rdi + rdx lies above rbp and rdi lies below the frame, so it stores 0xa0020307 to fs:[0x28] and executes int 0x45. The arguments were rdi = 0 (destination) and rdx = 0xfffffffffdffb309 (a negative length). The caller is app.exe+0x96635f. The last file opened was /app0/Media/Resources/unity default resources, just after StreamingAssets/aa/PS5/buffer_scene_scenes_all_*.bundle.
rip app.exe+0x95f5ed, a read of 0x00007ff99d83de58, after the same file opens.
rip app.exe+0x453b2e, a write of 0x0. The frames run app.exe+0x78cfd4, +0xc23a9b, +0xc89f38, +0xc7b1c3, +0xc7bed2, the same chain as fault 1 below its top frame.
All three faults share the frames app.exe+0xc89f38 and +0xc7b1c3. At the time, many IL2CPP threads are parked in libkernel.prx+0x44995.
Interpretation, not established: a negative length with a NULL destination, and wild pointers in neighbouring code, look like data being read or freed while another thread still uses it. #4973's file-position lock doesn't change the rate, so this is not that race. Other candidates are IL2CPP's garbage collector stopping and resuming threads, or a synchronisation primitive returning early. I haven't narrowed it further. The same thread and symptom in other Unity titles were attributed to #3861/#4973 on #3805; for this title, that fix isn't enough.
Thanks for the detailed reproduction. One check may separate malformed input from a synchronization race: does /app0/Media/Resources/unity default resources exist in this dump, and on a failing run does its sceKernelOpen succeed? If you can capture a lightweight trace for just that path (open result, each read offset/byte count/result, and the last successful read before the fault), it would show whether the deserializer receives a short/error read or complete data. A missing asset was one possible lead in the older Unity Loading.PreloadManager report (#3805), though it was never established there either. The 4/8 vs 5/8 rates don’t clearly show that #4973 changes this fault, so I wouldn’t infer either way from those samples.
Thanks. I checked both questions with a local-only logging build: mainc7601b797, plus logging in sceKernelOpen/Close/Read/Lseek/Pread/Fstat for that one path's descriptor.
The file exists.Media/Resources/unity default resources is 3,740,432 bytes in the dump, and sceKernelOpen succeeds every time (fd 4 or 6).
The reads are complete and identical in faulting and non-faulting runs. Over 6 runs of 40 s (5 faulted), the sequence was always:
open fd=4 flags=0x0 (tid A)
pread fd=4 at=0 n=65536 -> 65536 (tid A)
pread fd=4 at=327680 n=65536 -> 65536 (tid A)
pread fd=4 at=393216 n=65536 -> 65536 (tid A)
pread fd=4 at=327680 n=65536 -> 65536 (tid A)
close fd=4 -> 0 (tid B = Loading.PreloadManager)
There were no read, lseek or fstat calls on it. In faulting runs the fault follows that close on the same Loading.PreloadManager thread, for example app.exe+0x453b2e writing to 0x0.
So the deserializer gets complete data for this file, and it isn't a short or error read here. The fault comes after the file has been consumed and closed.
One run differed. The file was opened a second time later and got fd 0; then pread at=0 n=65536 and pread at=1075060 n=113428 both returned in full. That run ended with FATAL: UCRT invalid parameter on another thread, at libc.prx+0xb4b8 (host libc) called from libc.prx+0xaf5da. I'm not sure that is the same problem, but a file getting descriptor 0 may be worth a look on its own.
Thanks, this rules out a missing or short unity default resources read on both faulting and successful runs. The close immediately before the null write is useful timing, but the complete, identical reads mean I don't see a file-I/O change justified by this trace alone.
The fd-0 run may be a separate clue: the guest descriptor checks I found treat only negative values as invalid, so descriptor 0 is valid here. If that UCRT invalid-parameter report recurs, a stack or the invalid-parameter arguments would help identify which CRT call rejected them; I wouldn't tie it to the intermittent null write yet.
If you have time for another series: two open PRs change libkernel behaviour that could fit your "synchronisation primitive returning early" candidate. I haven't run Cult of the Lamb, so this is a guess.
Thanks @EagleBearerYS, I ran that series. maina453108cf was compared with each PR merged onto it, in alternating 40 s runs (Windows 11, same relinked app.exe, only the libraries swapped):
#4899's low first count didn't hold up over 10 more rounds, so none of the three clearly changes the rate. The faults keep the same mix of shapes with every set: 0xc0000005 on Loading.PreloadManager, abort(), and UCRT invalid parameter. #5412 and #5312 only had 6 runs each, so a smaller effect from them isn't ruled out.
Thanks for running the series. I read it the same way: none of the three clearly changes the fault rate, and #4899's early dip didn't hold over the longer series. With 6 runs each, a small effect from #5412 or #5312 isn't ruled out, but nothing here points to either of them.
Activity
MarcZX10 commentedon Oct 13, 2026
Thanks for the detailed reproduction. One check may separate malformed input from a synchronization race: does
/app0/Media/Resources/unity default resourcesexist in this dump, and on a failing run does itssceKernelOpensucceed? If you can capture a lightweight trace for just that path (open result, each read offset/byte count/result, and the last successful read before the fault), it would show whether the deserializer receives a short/error read or complete data. A missing asset was one possible lead in the older UnityLoading.PreloadManagerreport (#3805), though it was never established there either. The 4/8 vs 5/8 rates don’t clearly show that #4973 changes this fault, so I wouldn’t infer either way from those samples.p3n1cillin commentedon Oct 13, 2026
Thanks. I checked both questions with a local-only logging build:
mainc7601b797, plus logging insceKernelOpen/Close/Read/Lseek/Pread/Fstatfor that one path's descriptor.Media/Resources/unity default resourcesis 3,740,432 bytes in the dump, andsceKernelOpensucceeds every time (fd 4 or 6).read,lseekorfstatcalls on it. In faulting runs the fault follows that close on the sameLoading.PreloadManagerthread, for exampleapp.exe+0x453b2ewriting to0x0.So the deserializer gets complete data for this file, and it isn't a short or error read here. The fault comes after the file has been consumed and closed.
One run differed. The file was opened a second time later and got fd 0; then
pread at=0 n=65536andpread at=1075060 n=113428both returned in full. That run ended withFATAL: UCRT invalid parameteron another thread, atlibc.prx+0xb4b8(host libc) called fromlibc.prx+0xaf5da. I'm not sure that is the same problem, but a file getting descriptor 0 may be worth a look on its own.MarcZX10 commentedon Oct 13, 2026
Thanks, this rules out a missing or short
unity default resourcesread on both faulting and successful runs. The close immediately before the null write is useful timing, but the complete, identical reads mean I don't see a file-I/O change justified by this trace alone.The fd-0 run may be a separate clue: the guest descriptor checks I found treat only negative values as invalid, so descriptor 0 is valid here. If that UCRT invalid-parameter report recurs, a stack or the invalid-parameter arguments would help identify which CRT call rejected them; I wouldn't tie it to the intermittent null write yet.
EagleBearerYS commentedon Oct 14, 2026
If you have time for another series: two open PRs change libkernel behaviour that could fit your "synchronisation primitive returning early" candidate. I haven't run Cult of the Lamb, so this is a guess.
sceKernelSignalSemahands its tokens to the waiters already queued. Onmain, asceKernelPollSemaorsceKernelWaitSemathat runs first can take them, so a queued waiter can time out or keep waiting. fix(libkernel): release event flag waiters when the pattern is set #4899 does the same for event flags.setjmp/longjmpsave and restore the signal mask. That would matter if IL2CPP's collector stops threads with signals.If the fault rate changes with either of them merged into
main, that would narrow it down.p3n1cillin commentedon Oct 14, 2026
Thanks @EagleBearerYS, I ran that series.
maina453108cfwas compared with each PR merged onto it, in alternating 40 s runs (Windows 11, same relinkedapp.exe, only the libraries swapped):main#4899's low first count didn't hold up over 10 more rounds, so none of the three clearly changes the rate. The faults keep the same mix of shapes with every set:
0xc0000005onLoading.PreloadManager,abort(), andUCRT invalid parameter. #5412 and #5312 only had 6 runs each, so a smaller effect from them isn't ruled out.AI-assisted: yes (Claude Code)
EagleBearerYS commentedon Oct 14, 2026
Thanks for running the series. I read it the same way: none of the three clearly changes the fault rate, and #4899's early dip didn't hold over the longer series. With 6 runs each, a small effect from #5412 or #5312 isn't ruled out, but nothing here points to either of them.