The memmove length was computed from size_ after ExtendByOne() had
already bumped it, so it moved (oldSize - pos + 1) elements instead of
(oldSize - pos) - reading one uninitialized element past the old data
and writing one element past the new logical size. Currently masked
by ExtendByOne()'s growth policy always leaving capacity slack, but
a real overflow waiting for that assumption to not hold. Now captures
the old size before extending.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
next_crlf_offset() called peek() one byte past the currently buffered
data whenever a '\r' was the very last byte received (a normal TCP
fragmentation boundary) - peek() has no way to signal "not enough
data yet" and just asserts. Now checks there's actually a next byte
before peeking.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
next() would read a truncated lead byte's "second byte" unconditionally,
even when that byte was actually the string's null terminator - leaving
index_ one past the terminator, so a subsequent end()/next() call read
one byte out of bounds. Now checks for the terminator before consuming
it, returning INVALID without advancing past it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
RIFFReader::ReadData() trusted its count argument completely and
memcpy'd straight from the internal buffer with no bounds check.
Hardened it to clamp against the buffer and zero-fill any shortfall,
as defense in depth.
The actual reachable bug was in BackgroundAudio.cpp: it read a WAV
'smpl' chunk into a vector sized by GetCurrentChunkSize(), then
unconditionally indexed smplData[28] (and, for the loop array,
smplData[36]) with no check that the chunk was actually that large -
a short/corrupt chunk in a game's background-music WAV caused a heap
OOB read. Also fixes &smplData[0] being UB when the chunk is empty.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
These dereferenced get()'s result unconditionally, unlike the
two/three-arg "OrDefault" overloads which check. Hit on externally
sourced JSON: UI/Store.cpp reads the remote homebrew-store listing,
UI/DriverManagerScreen.cpp reads user-supplied GPU driver package
metadata - a field simply missing from either crashed the app instead
of failing gracefully.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
pngLoadPtr allocated the decoded buffer directly from attacker-controlled
PNG IHDR dimensions with no upper bound, so browsing a crafted game icon
or savedata could trigger a multi-gigabyte allocation.
- Add maxWidth/maxHeight parameters to pngLoadPtr (default 8192x8192)
and reject images larger than the limits.
- Thread the limits through LoadTextureLevelsFromFileData,
CreateTextureFromFileData, and CreateTextureFromFile.
- Limit game icons to 256x128 in GameInfoCache and IconCache.
FixedSizeQueue::DoState serializes the entire fixed backing store. For
the sceAudio channel queues that is 512KB per channel (32768*8 s16
samples), or ~4.6MB of mostly dead bytes in every savestate across the
nine channels - the live sample count at any moment is normally a few
KB. This addresses the existing TODO in DoState.
Add DoStateCompact(), which stores only the live [head, head+count)
region and restores it linearized at the front of storage. A wrapped
live region is written as its two pieces in pop order; since the POD
DoArray path writes raw bytes with no per-element or per-call header,
the single linear read on load consumes them identically. The count is
validated on load and a bad value fails the load cleanly via
p.SetError.
AudioChannel bumps its section to v3 to use the compact form; old
states still load through the unchanged full-storage path. This shrinks
every savestate by several MB uncompressed and cuts the copy/compress
cost of each save, including the rewind feature's periodic states.
Check the ZIM header, dimensions, mip count, allocation arithmetic,
and uncompressed payload size before allocating or copying image data.
This prevents crafted texture files from overflowing the image buffer.
* Improve a couple of on-screen buttons (menu, fastforward)
* Fix the new continue button, oops
* Add some missing translations
* Split a translation string to make portrait look better
* More GameScreen redesign
* Don't accidentally go into game-specific mode
* Fix layout issue with popupscreens, fix context menu positioning
* One more icon