Skip to content

Kena (PPSA01746) on Windows: null global slot written by a title setter at app.exe+0x1c7a46b #4073

Open

Description

@xXPBSXx

Kena: Bridge of Spirits (PPSA01746, Unreal Engine) on Windows, main plus open PRs (#419 + #425 in one run, #423 in others; the crash was also seen in the main session's notes before those PRs), 60 to 120 s per run: the title regularly ends with

FATAL: unhandled exception 0xc0000005 ... rip app.exe+0x1c7a46b   write of 0x0

in a different run the fault is instead a read of address 0 at app.exe+0x57378d7 on TaskGraphThreadHP 12. Both times the last title-visible log line before the fault is [SAVEDATA:native] dirNameSearch ... hit=0 set=0 -> 0x00000000. That is a coincidence I have not tested.

What app.exe+0x1c7a46b is (static, from the relinked image, no debugger run): a tiny setter, *(global_slot) = rdi, where global_slot is a pointer variable at 0x148f78048 (ELF vaddr 0x8f68048, which lies beyond the file-backed part of the second RW segment, i.e. zero-initialised .bss). The only reference to that address in the whole .text is this setter, and the import registry has no relocation that targets it, so nothing in the title's code, nor a relocation we apply, ever fills that pointer: it is 0 when the setter runs and the store faults.

The setter's caller (app.exe+0x1c1ba74, frame chain +0x1c1ba79 in the crash dump) walks a global array of objects (count at 0x148f777f8, array pointer at 0x148f77230), calls a virtual method at vtable offset +0x90 on each one, remembers the last object for which it returns 0, and hands that object to the setter; if none qualifies it logs an error with source line 1741 instead. So the title is selecting "the active one" of a set of objects and storing it into a slot whose pointer was expected to exist already.

Not established: which object or subsystem the slot belongs to, and why the pointer is null (a missing initialisation that should happen in an earlier title call, for example one of our APIs failing silently, or ordering). I did not run a debugger on it. A plain-main run (without any open GPU PR) for this title has not been done by me in this session, the earlier note of the crash predates those PRs.

AI-assisted (Claude Code).

Activity

  1. xXPBSXx commented on Oct 11, 2026

    @xXPBSXx
    ContributorAuthor

    Plain main check: main a672688 plus only #4021 (the Windows Socket.cpp build fix; no #419, #425 or #423), relinked and run for 120 s, ends with the same 0xc0000005, write of 0x0 at app.exe+0x1c7a46b. So this crash does not depend on any of the open GPU PRs. (The other, read-of-0 fault at app.exe+0x57378d7 was seen with #423 merged; I did not see it in this run.)

    AI-assisted (Claude Code).

  2. xXPBSXx commented on Oct 12, 2026

    @xXPBSXx
    ContributorAuthor

    Search for what should have filled the slot (static, from the original eboot.bin.esbak and the relinked app.exe; nothing run):

    • The setter's bytes are identical in the original ELF and in the relinked image (48 8b 05 dd db 2f 07 48 89 38, so the relinker did not change the access): it is mov rax, [slot]; mov [rax], rdi with slot at ELF vaddr 0x8f68048.
    • No instruction anywhere in the 100 MB of code takes the address of 0x148f78048 or of its neighbour 0x148f78040 with lea, and the only instruction that touches slot at all is that one load. The neighbouring variables are initialised by ordinary code: 0x...40 is stored by the function right before the setter (app.exe+0x1c7a399; that function creates an object, then sets the 0x40000000 flag in its object-table entry, which looks like an Unreal root-set flag, and keeps the object in 0x...40), 0x...50 is a one-byte initialised flag (+0x1c79a17), and 0x...10/18/20 are set by registration calls in a static-initialiser block (+0x1c88d7a...).
    • Loader side: I parsed DT_RELA (943,005 entries: 933,362 RELATIVE, 9,612 R_X86_64_64, 31 GLOB_DAT) and DT_JMPREL (2,034 entries, all type 7): no relocation has r_offset in 0x8f68040..0x8f68050, no addend equals the slot address, and the 8-byte value of the address (ELF or PE form) occurs nowhere in the file. The slot lies in the zero-filled tail (bss) of the second RW segment (file-backed up to 0x8e09360, memory to 0x9152...).
    • Startup: _start (0x80) runs _init (0x10), which walks an empty DT_INIT_ARRAY range and then a .ctors-style list from 0x8d368c8 downwards until a -1 sentinel; nothing in what I looked at writes the slot.

    So no static initialiser, relocation or table writes this slot; the only place it could be set is code that reaches it by a computed address or from another module, neither of which I found. What I did not do is run the title with a watchpoint on the slot (gdb -batch under the game lock) to see whether anything writes it at runtime; that is the next check, and it would also show whether the setter is reached on the console-like path at all (its caller only calls it when a candidate object was found, otherwise it logs and aborts).

    AI-assisted (Claude Code).

  3. xXPBSXx commented on Oct 12, 2026

    @xXPBSXx
    ContributorAuthor

    One run under the game lock with a hardware watchpoint on the slot (gdb -batch with a short Python script; starti, module base taken from the .elf0 section address minus 0x10000, slot at base + 0x8f78048; the first attempt had the wrong base and is discarded): main a672688 + #4021, Windows, 240 s limit. The watchpoint was set (Hardware watchpoint 1) and never fired, and in this run the title did not reach the setter either: the process ended after the usual start-up output (Vulkan device, shader work) with all threads exiting with 0x80000003 (a breakpoint exception), not with the 0xc0000005 write fault. So this run neither shows a writer of the slot nor the crash; under the debugger the timing differs from the plain runs, and I do not draw a conclusion about the slot from a run that ends before the setter. I did not get a second run.

    Possibly relevant, seen in the start-up output of this run: Project file not found: ../../../Kena/Kena.uproject right after Final commandline, and sceSysmoduleLoadModule unknown id: 295 / 271 (our libSceSysmodule logs unknown ids and returns 0). I do not know whether either matters for the slot.

    AI-assisted (Claude Code).

  4. xXPBSXx commented on Oct 12, 2026

    @xXPBSXx
    ContributorAuthor

    Re-check on main ceb342b94 (no open PR), Windows 10, GCC, RTX 4080 SUPER, one 60 s run: the same fault, 0xc0000005 at app.exe+0x1c7a46b, write of 0x0. Import audit: 0 absent imports. No new information beyond the description.

    AI-assisted (Claude Code).

  5. xXPBSXx commented on Oct 12, 2026

    @xXPBSXx
    ContributorAuthor

    Long run (240 s limit) of Kena on main e7c70a2 (+ #4408, #3840, no #423/#425), relinked fresh, 0 absent imports: it faults again at app.exe+0x57378d7 (read of 0x0, TaskGraphThreadHP 8), the second crash site from the earlier runs, not the setter at +0x1c7a46b this time. So on current main both stops still occur (the setter one in the plain-main run before, this one here); I have no new information on the cause.

    AI-assisted (Claude Code).

  6. oneandonlydean commented on Oct 14, 2026

    @oneandonlydean
    Collaborator

    #5479 and #5573 are on main now (guest addresses above the user address space on Windows, and fused geometry programs). Does PPSA01746 still fault at app.exe+0x1c7a46b or app.exe+0x57378d7 on current main?

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