At 0.7f the stale stop was already excluded by the position comparison
(0.5 >= 0.7 fails), leaving the epoch conjunct of the stop walk
uncovered. At 0.3f the position check passes and only the epoch match
keeps the walk from splicing past the stale stop; removing the conjunct
aborts guest_font_graphics.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Same DrawupPackColor fix as on the parent branch: NaN (admitted by
DrawupColorValid) is undefined through static_cast<int32_t>; firmware
converts with vcvttss2si into 64-bit registers, so an invalid channel
contributes a zero byte from the indefinite value's low dword. Assert
the packed stop color for a NaN channel (0x80800080) and correct the
FlatColor NaN expectation to 0x00000000. Verified under
-fsanitize=float-cast-overflow -fno-sanitize-recover on Linux.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
GraphicsAppendGradientSegment computed unitUsed % unitSize ahead of the
unitSize==0 check that selects 0x804600a0, leaving the guard dead behind
an undefined division. The firmware body carries the same defect (the
unguarded div at 0x20703 faults before its own dead 0x208fa branch), but
on the host the check is the only defined outcome for a corrupt frame,
so hoist it ahead of the first modulo; behaviour on every valid frame
(unitSize is always positive after object init) is unchanged. Adds the
zero-size regression case.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
sceFontGraphicsAppendGradientSegment decodes from the 4.03 libSceFont
body at 0x20500: sorted-inserts a 0x18-byte color-stop node into the +8
chain of linear (0x20) and radial (0x30) gradient records while
node->+4 == record->+4 and position >= node->+0x10. Stop records live in
a unit byte stream built from the per-object segment arena at
object->+0x10 (+0xc0 descriptor, mutex at +0x40, stats +0x48/+0x4c),
allocated by the span allocator at 0x1b5e0 (12-byte nodes: count(22b),
chain index(21b), span end(21b); index 0 is the sentinel). Units chain
through frame->+0x18/+0x20 with byte position in frame->+0x10/+0x14;
sub-0x18 tails get a 0xff pad record plus a zeroed tail. Validation
order, error codes (0x80460020/0x80460086/0x80460002/0x804600a0), NaN
acceptance, stats updates skipped on alloc failure, and the pad loop's
abandon-on-failure all follow the disassembly; guest_font_graphics
covers insert order, epoch stop, pads, unit boundaries and exhaustion.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
AnyPS5 has no Remote Play or Share Play CPU budget service, and the
console's acquire and release results, a repeated acquire and a release
without an acquire are unmeasured, so the six exports throw on every call
as they do on main instead of reporting a made-up hold.
The guest test now asserts that all six calls throw, and the debt entry
moves to Unknown function info with the unresolved contract.
Firmware 4.03 re-disassembly of the drawup bodies fixes three
transliteration errors:
- Option1Flags[1] is 0x3000, not 0x2000: the option1 jump table at
0x37fcc routes index 1 to case code that ors 0x2000 then falls into
or 0x1000.
- Sealed paths run the shared error epilogue (store at frame+4 and
invoke the registered callback), like every other error path; use
DrawupRecordError instead of a bare return.
- DrawupPoolAllocate returns memory + completingNodeIndex*slotSize
(0x1bcc0 marks slots start..start+count but returns the node whose
span finished the run), not the run's first slot.
The 13.42 emulator report matches on all three; its callback
suppression and +0x20 pool entries are firmware differences, not
deviations here.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
DrawupPackColor converted channel floats with static_cast<int32_t>,
which is undefined for NaN — the same input DrawupColorValid admits.
The firmware bodies pack with vcvttss2si into 64-bit registers, whose
invalid-conversion result is 0x8000000000000000; the low dword the
packing ORs in is 0, so an unrepresentable channel contributes a zero
byte. Implement the conversion explicitly: in-range values truncate
through int64_t, everything else contributes 0. The FlatColor NaN
regression now checks the firmware-faithful packed word (0x00000000
instead of the int32-indefinite 0x80000000 the old codegen happened to
emit). Verified under -fsanitize=float-cast-overflow
-fno-sanitize-recover on Linux: clean run, test passes.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
NIDs s2eGsgUF9vk (_ZnamSt11align_val_tRKSt9nothrow_t) and v09ZcAhZzSc
(_ZdaPvSt11align_val_t) forward to the libc exports of the same names
instead of throwing.