1 Commits
Author SHA1 Message Date
Gary Riches 3c0f213f2d Version 1.0.3: a NaN no longer faults the arctangent table
A player's console closed in Dragon Roost Cavern with SIGSEGV in cM_atan2s,
called from himo_move (the ropes of the hanging platforms, d_a_mflft.cpp). A
platform whose ropes were cut on an earlier visit is created with them cut and
its rope points are simulated from values nothing has set; a NaN among them
becomes the index 0x80000000, which the GameCube's 32 bit address wraps to
entry 0 and x86-64 reads 4 GB below the table.

- c_math.cpp: U_GetAtanTable gives entry 0 for a NaN or a ratio outside the
  table.

Claude-Session: https://claude.ai/code/session_018jvMS8Y8okH8SDZUfd8MP1
2026-10-13 15:39:40 +01:00
3 changed files with 42 additions and 6 deletions

No files matched your search

+18 -5
View File
@@ -24,11 +24,13 @@ symbols on the HUD. Played on the console as far as the forest on Outset, the
scenes that follow it, and the boss room of Dragon Roost Cavern; nothing else
has been seen there.
**[Version 1.0.2](https://github.com/griches/PS5_SwitchWaker/releases/tag/v1.0.2)** fixes a crash when the boss of Dragon Roost Cavern appears, and
stops the whole class of fault behind it (an integer division by zero) from
ending the game anywhere else. [Version 1.0.1](https://github.com/griches/PS5_SwitchWaker/releases/tag/v1.0.1) fixed a stop on a black
screen at the end of the forest scene. See [Development](#development) for what
both were. Copy the [new release](https://github.com/griches/PS5_SwitchWaker/releases/latest) over the old folder; saves carry on.
**[Version 1.0.3](https://github.com/griches/PS5_SwitchWaker/releases/tag/v1.0.3)** fixes a crash in Dragon Roost Cavern, in the rooms with
the hanging platforms. [Version 1.0.2](https://github.com/griches/PS5_SwitchWaker/releases/tag/v1.0.2) fixed a crash when the boss of Dragon
Roost Cavern appears, and stopped the whole class of fault behind it (an
integer division by zero) from ending the game anywhere else. [Version 1.0.1](https://github.com/griches/PS5_SwitchWaker/releases/tag/v1.0.1)
fixed a stop on a black screen at the end of the forest scene. See
[Development](#development) for what
they were. Copy the [new release](https://github.com/griches/PS5_SwitchWaker/releases/latest) over the old folder; saves carry on.
A release is the title's folder with no game in it: the player copies their own `GZLE01` disc image (`.iso`, `.gcm` or `.ciso`) into
`/data/homebrew/PPSA99309/` beside `eboot.bin`, and the title finds it (the
@@ -180,6 +182,17 @@ Mac, the Switch) it does not show. The framework now reads only the low byte
([`f_pc_method.cpp` in the patch](ps5/patches/switchwaker.patch)). On the Mac, `COS_EVENT_SWEEP_FOLLOW=1` lets
`run.sh event-sweep` go on through a stage change an event asks for.
The crash that 1.0.3 fixes is a third one. A hanging platform of Dragon Roost
Cavern whose ropes were cut on an earlier visit is created with them cut, and
the rope points are simulated from values nothing has set. A NaN among them
reaches the arctangent table as an index: the conversion to an integer gives
0x80000000, which the GameCube's 32 bit address wraps back to the first entry
and x86-64 turns into a read 4 GB below the table. The lookup now gives the
first entry for a NaN or a ratio outside the table ([`c_math.cpp` in the patch](ps5/patches/switchwaker.patch)).
It was found from a player's photograph of the console's error message: the
two addresses in it, less the load address 0x400000, name `cM_atan2s` and
`himo_move` in the release's ELF.
The crash that 1.0.2 fixes is the same kind of difference. The boss of Dragon
Roost Cavern turns towards the player with a step count that is still zero the
first time, an integer division by zero: the GameCube and ARM give a quotient
+23
View File
@@ -48,6 +48,29 @@ index 0f1f94f..02eaf89 100644
if (scale > minStep || scale < -minStep) {
if (scale > maxStep) {
scale = maxStep;
diff --git a/game/src/SSystem/SComponent/c_math.cpp b/game/src/SSystem/SComponent/c_math.cpp
index 5129f61..8c7e218 100644
--- a/game/src/SSystem/SComponent/c_math.cpp
+++ b/game/src/SSystem/SComponent/c_math.cpp
@@ -111,7 +111,18 @@ static u16 atntable[] = {
/* 8024609C-802460D0 .text U_GetAtanTable__Fff */
u16 U_GetAtanTable(float f0, float f1) {
+#if TARGET_PC
+ // A NaN reaches this (the cut ropes of d_a_mflft.cpp). The conversion gives 0x80000000 on the
+ // GameCube and on x86-64: the GameCube's 32 bit address wraps back to entry 0, x86-64 reads 4 GB
+ // below the table and faults. Entry 0 here, as on the GameCube.
+ f32 ratio = f0 / f1 * 1024;
+ if (!(ratio >= 0.0f && ratio <= 1024.0f)) {
+ return atntable[0];
+ }
+ return atntable[(int)ratio];
+#else
return atntable[(int)(f0 / f1 * 1024)];
+#endif
}
/* 802460D0-80246270 .text cM_atan2s__Fff */
diff --git a/game/src/d/d_meter.cpp b/game/src/d/d_meter.cpp
index 05ecca5..292ce89 100644
--- a/game/src/d/d_meter.cpp
+1 -1
View File
@@ -10,7 +10,7 @@
"conceptId": "99309",
"contentBadgeType": 1,
"contentId": "UP9000-PPSA99309_00-WINDWAKER0000000",
"contentVersion": "01.000.002",
"contentVersion": "01.000.003",
"downloadDataSize": 256,
"gameIntent": {
"permittedIntents": [