Files
AnyPS5/docs/dev/debt/libSceJpegDec.md
T
hypermoistandClaude Opus 5.5 aeb2346bb8 fix(libSceJpegDec): keep an input stream alive for the call reading it
parseStream and decodeStream held a reference into the stream map
outside streamMutex while the guest's input callback ran. A callback
that deleted the handle, or a delete or new parse on another thread,
erased the stream under the running call.

- The map holds shared streams; each call keeps its own stream until
  it returns, and the callback still runs outside streamMutex.
- A call that reaches a stream another call is still reading throws,
  as the console's answer is not known; the debt entry says so.
- Tests: deleting the handle from the callback during a parse and
  during a decode, and a decode re-entered from the callback.
- The test no longer requires parse operation 0x11 to throw.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 23:03:57 +13:00

2.1 KiB

libSceJpegDec technical debt

Functional

  • libSceJpegDec: work-memory size, alignment, creation checks, image-info fields, progressive coefficient-buffer capacity, row-buffer capacity and scaled dimensions are recovered from the native module. The host still allocates its decoder storage separately rather than using the guest work and coefficient regions. Malformed-header diagnostics and output mutation on failure are not fully matched.
  • sceJpegDecDecode: decode mode 1 and pixel formats 9, 10 and 11 remain unimplemented and throw. Exact decoded pixel values and color conversion are not verified against the native decoder. One title (PPSA29866) disassembled for this entry has one call site (0x2c111d); it passes a null imageInfo and a parameter structure with decode mode 0, down-scale 1 and pixel format 0, and hands the result to another function whose handling of a negative result was not read. In the parameter structure built around this call site, mode 1 and formats 9, 10 and 11 do not show up; whether a down-scale of 1 means no scaling was not compared.
  • sceJpegDecDecodeWithInputControl (libSceJpegDec): decode mode 1, pixel formats 9 to 11, unlisted parse down scale, decoding without parse and decoding at another down scale throw. A stream that ends before the frame header, or cannot form one, returns 0x80650012 (measured on PS5 firmware 13.42 libSceJpegDec.sprx; sceJpegDecParseHeader on the same bytes returns 0x80650010 or 0x80650002); callback call counts differ because the firmware (13.60 disassembly) refills its 2 KiB buffer when under 0x3F0 bytes remain, whereas this implementation pulls in 2048-byte blocks. Streamed bytes reside in host memory; freeing work memory without sceJpegDecDelete leaves them allocated. A call reaching a stream another call on the handle is still reading (a decode from its own input callback) throws; the console's answer is unknown. A delete or new parse during a call leaves it reading its own stream.