Skip to content

Commit 6ff5c3f

Browse files
authored
Fix out-of-bounds theme-color read for the special 7th race circuit (#16)
The single-race and circuit-race screens expose 7 selectable circuits, but g_singleRaceVisualStateMap only encodes the 6 standard ones (24 = 6 * 4). Both callers pass circuitIndex * 4 + raceIndex, so selecting the special 7th circuit (cf. the m_circuitIndex != 6 special-casing in CircuitRaceScreen::Update) yields index 24..27 and reads past the table. This is a latent bug in the retail binary, verified byte-matching with reccmp (ApplyThemeColor/CreateWidgets/WrapIndex 100%, UpdateRacePreview/ScrollPrevious 100% effective, datacmp 0 issues). Retail happened to read harmless adjacent static data, but the port trips ASAN/UBSAN. Guard the lookup in ApplyThemeColor (the shared choke point) and give the special circuit a dark purple border.
1 parent 163c47a commit 6ff5c3f

1 file changed

Lines changed: 9 additions & 0 deletions

File tree

LEGORacers/src/menu/screens/singleraceselectbase.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,5 +183,14 @@ void SingleRaceSelectBase::SetPreviewDriver(const LegoChar* p_name)
183183
// FUNCTION: LEGORACERS 0x00488cb0
184184
void SingleRaceSelectBase::ApplyThemeColor(LegoS32 p_index)
185185
{
186+
// Map covers only the 6 standard circuits (24 = 6 * 4); the special 7th circuit (cf.
187+
// m_circuitIndex != 6 in CircuitRaceScreen::Update) has no entry, so callers pass index
188+
// 24..27 for it -- a latent retail OOB read (matching). Give it a dark purple border.
189+
if (p_index < 0 || p_index >= static_cast<LegoS32>(sizeOfArray(g_singleRaceVisualStateMap))) {
190+
VisualStateColor purple = {{0xff600040}}; // RGB(64, 0, 96), packed A,B,G,R
191+
m_borderFrame.SetBorderColors(&purple);
192+
return;
193+
}
194+
186195
m_borderFrame.SetBorderColors(&g_singleRaceVisualStates[g_singleRaceVisualStateMap[p_index]]);
187196
}

0 commit comments

Comments
 (0)