D130: stage fontchar fields before in-place 24->32B relayout (C2 Facility+Runway)

romdataFixupFont re-lays out the N64 24B fontchar array into the PC 32B
array in place; for glyphs 0/1/2 dst overlaps src by less than the 24B
read span, so a forward field write clobbered a later field's source
mid-loop (glyph 1 width = bswap(index), glyph 2 pixeldata -> wild ptr).
Facility's level title 'Chemical Warfare Facility #2' rendered '#' with
the wild pixeldata -> gDPLoadTextureBlock -> fast3d AV in import_texture_i8.

Fix: stage all six N64 fields in a local f[6] before writing any.
Not the model-GDL relocation the D124-Facility addendum suspected
(disproved; D124 entry + BRIEF-C2gdl-model-reloc premise corrected).

Verified: -level_34 0/~14 runs, -level_35 0/4 (was ~3/4);
-level_09/20/24 unregressed. Sweep 18 -> 20/21 PASS; only Jungle C2m
(gfx_sp_matrix explosion-DL G_MTX) remains.

Docs: D130 in PCPortResearch §F/§H, LEVEL-STATUS 20/21, HANDOFF M-18,
PORT-LEARNINGS §A (in-place relayout aliasing + negative glyph index).
This commit is contained in:
James Dansereau committed 2026-08-29 21:33:56 -04:00
1 parent 7159fff544
commit fda4c19159
5 files changed
+132 -28

No files matched your search

+11 -3
View File
@@ -501,10 +501,18 @@ void romdataFixupFont(u8 *blob, u32 n64Size)
for (i = n; i-- > 0;) {
const u8 *s = blob + N64_COFF + N64_CSTRIDE * i;
u8 *d = blob + ROMDATA_OFFSEXP(struct font, chars) + sizeof(struct fontchar) * i;
u32 k, o;
u32 f[6], k, o;
/* D130: PC stride (32) - N64 stride (24) = 8, so for the first few
* glyphs `d` overlaps `s` by less than the 24-byte read span and a
* field write clobbers a later field's source mid-loop (glyph 1's
* width came out as bswap(index), glyph 2's pixeldata as
* pcPixOff+(index-pixStart) -> wild pointer -> fast3d AV rendering
* '#'/'"'). Stage all six N64 fields before writing any. */
for (k = 0; k < 6; k++)
f[k] = romdataBswap32(*(const u32 *)(s + 4 * k));
for (k = 0; k < 5; k++)
*(u32 *)(d + 4 * k) = romdataBswap32(*(const u32 *)(s + 4 * k));
o = romdataBswap32(*(const u32 *)(s + 20));
*(u32 *)(d + 4 * k) = f[k];
o = f[5];
if (o != 0 && pixStart != 0 && o >= pixStart)
o = pcPixOff + (o - pixStart);
/* D51: on PC pixeldata is a u64 at d+24 (fontchar needs 8-align,