Runtime: async invocation stacks alias thread stacks, so every interrupt handler corrupts the interrupted frame's return address
I maintainer di solito rispondono entro 5 giorni
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 32/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- cpp
- Ambito
- operating-systems, reverse-engineering
Direzione di ricerca
Start in ps2xRuntime/include/ps2_runtime.h and ps2xRuntime/src/lib/ps2_runtime.cpp at reserveAsyncCallbackStack() and the two resets of m_asyncCallbackStackTop to PS2_RAM_SIZE. Trace how SetupThread/CreateThread pass stack address and size into EeScheduler and how GuestThread::stack is stored (top vs base). Done when async stacks are derived from declared thread extents, overlap is refused, and stacks entirely below the async floor are ignored so titles can take interrupts without clobbering $ra.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
What happens
PS2Runtime::reserveAsyncCallbackStack() carves stacks for asynchronous invocations (INTC/DMAC handlers, GS callbacks, alarms) downwards from m_asyncCallbackStackTop, initialised to PS2_RAM_SIZE (0x02000000):
ps2xRuntime/include/ps2_runtime.h--uint32_t m_asyncCallbackStackTop = PS2_RAM_SIZE;ps2xRuntime/src/lib/ps2_runtime.cpp:507and:976-- both reset it toPS2_RAM_SIZE
So the first reservation returns 0x01FFFFF0.
That is exactly where the guest's main thread stack lives. Measured at the first schedule in Ridge Racer V: sp=0x1fffff0. The "dedicated" invocation stack therefore aliases the stack of the very thread it interrupts, and each asynchronous handler overwrites the frames of the function it interrupted.
What it costs
Captured with a hardware watchpoint on 0x01FFFFA0:
--- write 1: 0x01FFFFA0 <- 0x0021DF40 ---
#0 rrv_00220470 <- its prologue saves its return address
#1 PS2Runtime::dispatchGuestBranch
#2 rrv_0021DE90 <- the game loop
#3 EeScheduler::run
--- write 2: 0x01FFFFA0 <- 0x00000000 ---
#0 rrv_0021FE88 <- interrupt handler, running as an invocation
#1 EeScheduler::run
FUN_00220470 keeps its return address at 16($sp) with sp = 0x01FFFF90, i.e. 0x01FFFFA0. The handler, started on an invocation stack beginning at 0x01FFFFF0, lays its own frame there and writes its $ra -- zero, as expected for an invocation -- right on top of it.
FUN_00220470 is then resumed at its epilogue, reloads $ra, and finds zero. jr $ra jumps to address 0. The scheduler sees pc == 0 with an empty invocation list and puts the thread to sleep; _start reaches its Exit. The game loop did not complete a single iteration.
Suggested fix
A constant reserve below the top of RAM proves the cause but is not a solution: nothing tells a constant how far down a thread stack reaches, and a game with many threads would exhaust the region.
The kernel already has the information. SetupThread (syscall 0x3C, InitMainThread) and CreateThread both receive a stack address and a stack size and pass them to EeScheduler. Derive the asynchronous region from the actual declared thread stack extents, and refuse the allocation when they would overlap.
Two traps worth knowing if you implement it:
- The meaning of
GuestThread::stackis not uniform -- see the companion issue aboutSetupThreadstoring a top whereCreateThreadstores a base. - A stack sitting entirely below the asynchronous floor constrains nothing. Ridge Racer V's
_spuCBThreadhas its stack at0x01DAD500, inside the game's.bssand below the0x01F00000floor; taking it into account pushed the ceiling under the floor, the allocation failed, and the runtime raised "EE invocation stack space exhausted". Only keep stacks whose top is above the floor.
Result after fixing it locally
| before | after | |
|---|---|---|
| game loop body completions | 0 | 2552 |
| main thread state | Dormant |
Running |
| GS kicks / primitives | 4 / 2 | 24 / 12 |
Any title that takes an interrupt during a nested call loses the interrupted frame's return address the same way.
Found while statically recompiling Ridge Racer V (NTSC-U, SLUS_200.02) with PS2Recomp.
Tested on commit 75d729ce; main was c5a9d02 at the time of writing, one README-only commit ahead.
Host: Windows 11 x64, clang-cl 22.1.3 + Ninja, MSVC toolset 14.51.36231, Windows SDK 10.0.26100.0, CMake 4.2.3.
None of these are specific to this game.
- Lingua principale
- C++
- Stelle
- 3.3k
- Fork
- 149
- Merge medio
- 5g 10h
- PR unite (30g)
- 4
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di ran-j/PS2Recomp
-
VU0 macro VSQI / VSQD: address and source registers swapped in generated codeForse già presa @yanm1103 l’ha presa 1 giorno fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 5 giorni
-
Runtime: SampleTexture casts unbounded or NaN texture coordinates to int, which is undefined behaviourForse già presa @luisbraganca l’ha presa 7 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
ran-j/PS2Recomp#273 · 2 commenti ·
I maintainer di solito rispondono entro 5 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
I maintainer di solito rispondono entro 5 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
I maintainer di solito rispondono entro 5 giorni
-
Runtime: writes to D_ENABLEW (0x1000F590) are never visible at D_ENABLER (0x1000F520), hanging any game that suspends the DMACForse già presa @luisbraganca l’ha presa 6 giorni fa. Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
ran-j/PS2Recomp#257 · 1 commento ·
I maintainer di solito rispondono entro 5 giorni
Tutte le issue di ran-j/PS2Recomp
Issue simili
-
Mac mini M6 (16 GB): Q2_0 streaming works - measured 11.7->27.2 tok/s + arena fix for sub-32 GB MacsAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
champion good first issue remake source/qq
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
metasequoiaime/msime-windows#1025 ·
I maintainer di solito rispondono entro 1 giorno
-
backlog bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
EchoTools/nevr-runtime#653 ·
I maintainer di solito rispondono entro 1 giorno
-
`--fail-require-skip` never fires: run_tests.py searches stdout, but the unittest binary writes the skip summary to stderrForse già presa Una pull request collegata a questa issue è aperta o già unita. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
InfiniTimeOrg/InfiniTime#2492 ·