Skip to content

Returnal (PPSA01285) on Windows: intermittent fault in a frame-pointer stack walk at app.exe+0x337aa9d (UE4 Main Thread, read of 0x8) #4239

Closed as not planned

Description

@xXPBSXx

Returnal (PPSA01285, Unreal Engine) on Windows, main d0ca839 and a672688, relinked from PPSA01285_elf, 0 absent imports: in 2 of 3 runs the title faults within the first seconds (the log has about 57 lines):

FATAL: unhandled exception 0xc0000005 on thread 'UE4 Main Thread'
  rip app.exe+0x337aa9d   read of 0x8   (rcx = 0)

The third run (60 s) did not fault.

What the instruction is (static, from the relinked image): app.exe+0x337aa40 is a stack-walk function. After clearing a 0x320-byte buffer it loads the return address [rbp+8], and then loops: store the address in a local array, rcx = [rcx] (next saved frame pointer), rax = [rcx+8] (that frame's return address), continue while the return address is non-zero, at most 100 entries. There is no check of rcx itself, so the loop only ends cleanly if the last frame in the chain has a zero return address and a valid frame pointer. If the chain ends in a null frame pointer, [rcx+8] reads address 8, which is the fault here (rcx = 0).

Hypothesis, not tested: on the console the bottom of a thread's frame chain is a valid frame with a zero return address; on this host the chain of the main thread continues into host start-up code or ends in 0, depending on the run. That would also explain why it is intermittent. I have not looked at how our thread start-up sets rbp, and I have not seen who calls the walker (the crash dump's chain shows frames up to app.exe+0x3339012).

AI-assisted (Claude Code).

Activity

  1. xXPBSXx commented on Oct 12, 2026

    @xXPBSXx
    ContributorAuthor

    Correction: the stack walk is the symptom, not the cause. Following the crash dump's frame chain in the relinked image (static, objdump; strings read from the image):

    What I have not established: which allocation fails and what our side returned for it. Our direct-memory pool is 13824 MiB (DIRECT_MEMORY_SIZE) and the flexible-memory budget is 448 MiB (FLEXIBLE_MEMORY_SIZE, Export.cpp; it prints [memory] flexible memory exhausted when it runs out, which none of my logs contain). I ran Returnal three more times with APS5_TRACE_MEMORY=1 (45 s each) and did not hit the fault again, so I have no trace of the failing call. The intermittence suggests the failure depends on timing or on the address-space layout of that run (not shown to be a race). Next step for whoever continues: keep running with APS5_TRACE_MEMORY=1 until the fault appears and read the last sceKernelAllocateDirectMemory/sceKernelMap* calls and their return codes before it.

    The same class may explain other UE title stops that were attributed to the title's libc fatal path (libc.prx.guest.prx+0x141b0): Demon Slayer on #4238 shows LowLevelFatalError [File:Unknown]; I have not looked at whether it is an out-of-memory message.

    AI-assisted (Claude Code).

  2. xXPBSXx commented on Oct 12, 2026

    @xXPBSXx
    ContributorAuthor

    Update from a 240 s run: Returnal (PPSA01285) faulted at the same place again (app.exe+0x337aa9d, UE4 Main Thread, read of 0x8) within the first seconds (57 log lines), so by now 3 of 5 plain runs on current main hit it; the other two ran without it. Nothing new on the cause; the out-of-memory reading above stands.

    AI-assisted (Claude Code).

  3. oneandonlydean commented on Oct 12, 2026

    @oneandonlydean
    Collaborator

    Does this still happen with the PlayGo chunk check from before #3238 (your one-line change on #3209)? The PS5 Out of Memory path is the one PPSA03001 and PPSA03490 reach since that merge.

  4. xXPBSXx commented on Oct 12, 2026

    @xXPBSXx
    ContributorAuthor

    @oneandonlydean Answer with numbers. I did not run the exact pre-#3238 one-line revert on Returnal; I ran the bound I propose in https://github.com/xXPBSXx/AnyPS5/tree/fix/playgo-bound-no-chunk-table (ids below 256 accepted without a chunk table, larger ids BAD_CHUNK_ID), 3 runs of 240 s each on main ffa198407 versus the same main plus that change (libraries hash-checked against the work directory's copy):

    • Plain main: 3 of 3 runs print PS5 Out of Memory (UsedPhysical about 9.28 GB, AvailablePhysical about 5.0 GB) and fault on UE4 Main Thread at app.exe+0x337aa9d (read of 0x8), after 57, 60 and 77 s of runtime.
    • With the change: 0 of 3 runs print that message or fault there. One run was still alive at 240 s; two ended after 136 and 146 s with abort() from compute shader ...: AGC graphics: storage image access to depth/stencil surface ... is not implemented (runtime_error, a different, later stop).

    So for this title the stack-walk fault is reached only through the out-of-memory path on current main, and the bound removes that path in these runs. The Returnal dump has no sce_sys/playgo-chunk.dat (an observation; I have not shown that this is why the loop runs). Sifu's measurements are in #3209 (comment) (the 6 of 6 clean runs with the change and the Demon Slayer comparison, 3 of 3 failing without and 0 of 3 with the OOM message, go into the PR text for that branch). Not tested: the exact pre-#3238 check on Returnal, Linux.

    AI-assisted (Claude Code).

  5. oneandonlydean commented on Oct 14, 2026

    @oneandonlydean
    Collaborator

    #4491 is on main: without a PlayGo file only chunk 0 is valid. Does Returnal still print PS5 Out of Memory and fault at app.exe+0x337aa9d on current main? If not, this can close.

  6. Tamalero commented on Oct 17, 2026

    @Tamalero
    Contributor

    A second title with this fault, on Linux, and a core dump that confirms the hypothesis above: the frame chain runs past the guest thread's first frame into AnyPS5's thread start-up, whose saved frame pointer is garbage.

    Title: LEGO Batman: Legacy of the Dark Knight (PPSA16833 v01.010.000). Build: main 5d9dcc42d + #6694 + #6699 + the sceWebBrowserDialogOpenForPredeterminedContent hunk of #6447, plus input-only changes. Linux, RTX 4090. Four runs segfaulted at the same instruction, each right after a large burst of shader-cache loads or compiles (a new area streaming in); other sessions, one of them 26 minutes long, ended normally. So it's intermittent here too, which fits a walk that only crashes when the chain's garbage value isn't readable memory.

    The faulting function (app.elf+0x3383eee) is the same kind of walker as yours: it starts from its own rbp, loads rcx = [rax+8] (the return address), stops when that is zero, stores at most 100 entries, and follows rax = [rax]. It never checks the frame pointer itself.

    The chain at the fault (from the core, frame pointer → saved frame pointer, return address):

    Frame Saved rbp Return address
    0–5 on the guest thread's stack app.elf (the walker and its callers)
    6 on the guest thread's stack libkernel.prx+0x95582, i.e. StartNativeThread right after its call *%r12 into the guest entry
    7 0x21 libc.so.6+0xac93f (glibc's thread start)

    Frame 7 is StartNativeThread's own frame; its saved rbp is whatever glibc's thread start left in the register (glibc doesn't keep frame pointers), here 0x21. The walker follows it and reads 0x29: SIGSEGV. Your Windows case (rcx = 0, read of 0x8) is the same chain ending in a different garbage value.

    A possible fix: before StartNativeThread calls the guest entry (Linux and Windows paths, and presumably wherever the guest main thread is entered), point rbp at a terminating frame record {saved rbp = 0, return address = 0} on the guest stack. Both walkers stop on a zero return address, so the chain would end there as it does on the console. I haven't written or tested that yet.

    Tested and written by Claude (AI assistant) on a contributor's machine.

  7. MarcZX10 commented on Oct 23, 2026

    @MarcZX10
    Contributor

    Two merged changes now cover the reported path on current main:

    Could you rerun Returnal on a fresh build of current main and report whether it still prints PS5 Out of Memory or faults at app.exe+0x337aa9d? If it proceeds, that would establish the reported stop is addressed; if it reaches another failure, the new log would define the next issue.

  8. oneandonlydean commented on Oct 26, 2026

    @oneandonlydean
    Collaborator

    Two fixes for this are on main now: #4491 (18c438b) for the out-of-memory path and #7123 (cb1d6e5), which ends guest thread frame chains at a zero record so the frame walker stops cleanly (this is the Linux core dump Tamalero posted above). Could you or Tamalero retest on current main and say whether the fault at app.exe+0x337aa9d / "PS5 Out of Memory" still appears? If it is gone I'll close this.

  9. oneandonlydean commented on Oct 29, 2026

    @oneandonlydean
    Collaborator

    No reply to the retest request, so closing this. The out-of-memory path (#4491, 18c438b) and the frame-chain terminator that stops the walker cleanly (#7123, cb1d6e5) are both on main. If the fault at app.exe+0x337aa9d or "PS5 Out of Memory" still shows on current main, please open a new issue with the log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions