# Phase 1.0B runtime and exit contract Status: source-bound offline contract; firmware-9.60 behavior remains unproven until a separately authorized one-shot run. ## Stateful lifecycle The status record tracks platform, frontend, SDL, video, input, audio, core, threads, buffers, direct memory and device handles. Initialization records each subsystem once in a bounded stack. Cleanup may touch only an initialized bit, runs once, and verifies reverse order. An order violation is sticky `E120`, duplicate init is `E119`, duplicate cleanup is `E121`, and a cleanup failure is `E122`. Host fault injection covers every partial-init boundary, every per-subsystem cleanup failure and an out-of-order cleanup. Video cleanup stops future flips, destroys the software surface and event queue, closes VideoOut, releases direct memory, then clears handles. Input cleanup closes Pad before its state is cleared. Audio cleanup stops the SDL worker before AudioOut close and records the elapsed cleanup time. The pinned public SDL source exposes release of direct memory but no separately evidenced direct-memory unmap primitive; this remains a declared cleanup uncertainty. ## Exit alternatives | Option | Exact evidence | Destructors/cleanup | Continuation | Decision | |---|---|---|---|---| | return from `main` | SDK `crt/crt.c:133-146,153-170,196-220` | SDK `.fini` runs | a hijacked process returns through the synthetic address placed by elfldr | rejected | | `payload_exit` | SDK `crt/crt.c:174-180`, `payload.h:45-51` | long-jumps into CRT | still reaches `payload_terminate`; hijacked route returns | rejected | | libc `exit` | imported and used by SDK `payload_terminate` only for a non-hijacked process | libc exit semantics; would bypass the remaining SDK payload path when called directly | process termination expected | not selected | | libc `_Exit` | public libc import in the final ELF; direct call from smoke `main` | all RetroArch/SDL cleanup runs first; no process destructors after call | no synthetic return | selected | The selected method is compile-time `CHIMERA_PS5_EXIT_PROCESS_EXIT=1`. After `rarch_main` completes, `main` sets `S15` and reaches one smoke-owned `_Exit(result)` call. The smoke SDL overlay disables the dynamic API and sets `SDL_ASSERT_LEVEL=0`, removing SDL's secondary `SDL_ExitProcess` callsites. Disassembly and the undefined-symbol inventory bind this decision. It does not reboot, launch another process, retry or write a device file. The SDK CRT still imports `exit` for its own pre-`main` initialization-failure termination; that separate startup path is not represented as the selected smoke exit. ## Loader relationship Hardened elfldr commit `197623058f509eddde18868dafcb92fdcac66464` spawns a separate child, writes the pre-injection RIP to `rsp-8`, enters the payload at `_start`, and on the controlled route waits under a bounded watchdog (`elfldr.c:381-410,643-768`; `socksrv.c:128-157`; `ps5_controlled.c:186-215`). `_Exit` terminates that child instead of resuming the synthetic continuation. This is stronger source evidence than returning, but it is not device evidence. Remaining exit risks are: - SDK CRT initialization and temporary runtime patches occur before `main`; - SDK CRT startup resolves runtime-loader functions and may conditionally load `libSceSysmodule` before entering RetroArch; - firmware-9.60 libc `_Exit` behavior in this exact injected child is unobserved; - a blocked AudioOut call or SDL join can prevent reaching `_Exit`; - the controlled loader route itself is not authorized or exercised here; - ending the child can end the current host/jailbreak session, which is a session risk rather than an installation guarantee. No execution-review bundle has been produced.