mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-21 18:29:05 +02:00
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>
65 lines
1.9 KiB
C++
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();
|
|
}
|
|
}
|