Files
ppsspp/Core/HW/BufferQueue.cpp
T
Henrik RydgårdandClaude Opus 5.5 43f7674f9c SaveState: Check the audio and media modules' values from a state
A review of their savestates found nothing wrong with a normal save and
load, but a broken or crafted state could crash or write out of bounds:

- Atrac2's context pointer was dereferenced and its SAS buffer index used
  unchecked. Atrac v1's file size sized an allocation before it was known
  to be in the file, and its first buffer could be larger than the file.
- MediaEngine's MPEG header size and read position index a fixed array,
  and its ringbuffer size sizes buffers.
- AuCtx's PCM buffer must hold two frames, as the game side requires. And
  AuDecode compared a decoded frame with the whole PCM buffer instead of
  the half it fills, so a frame between the two zero-filled a negative
  size.
- BufferQueue's fill level, VAG block positions (now ending the voice,
  like the other bad VAG state), sceAudiocodec's context count, the SRC
  mix frequency (divided by), and old sceMpeg states' ringbuffer address.
- SAS decoding with an atrac id that has no atrac crashed after warning.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 00:20:24 +02:00

65 lines
1.9 KiB
C++

// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/Serialize/SerializeFuncs.h"
#include "Common/Serialize/SerializeMap.h"
#include "Core/HW/BufferQueue.h"
void BufferQueue::DoState(PointerWrap &p) {
auto s = p.Section("BufferQueue", 0, 2);
const int allocatedSize = bufQueueSize;
Do(p, bufQueueSize);
Do(p, start);
Do(p, end);
if (p.mode == PointerWrap::MODE_READ && bufQueue) {
// Normally the owner allocated the same size, but don't write past the buffer if not.
const int size = bufQueueSize;
if (size <= 0 || start < 0 || end < 0 || start > size || end > size || !p.CheckRead(size)) {
bufQueueSize = allocatedSize;
clear();
p.SetError(PointerWrap::ERROR_FAILURE);
return;
}
if (size != allocatedSize) {
const int savedStart = start;
const int savedEnd = end;
alloc(size);
start = savedStart;
end = savedEnd;
}
}
if (bufQueue) {
DoArray(p, bufQueue, bufQueueSize);
}
if (s >= 1) {
Do(p, ptsMarks);
} else {
ptsMarks.clear();
}
if (s >= 2) {
Do(p, filled);
if (p.mode == PointerWrap::MODE_READ && (filled < 0 || filled > bufQueueSize)) {
p.SetError(PointerWrap::ERROR_FAILURE);
filled = calcQueueSize();
}
} else {
filled = calcQueueSize();
}
}