SaveState: Reject implausible event counts, ids and CPU speed from a state

They came straight from the file: a CPU frequency of 0 divided by zero,
and counts or ids sized tables of up to tens of gigabytes, or tripped an
assert. A file like that now fails to load like any other broken state.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-19 20:17:47 +02:00
1 parent 79d340f4fe
commit eec6afaeca
2 files changed
+19 -1

No files matched your search

+17
View File
@@ -44,6 +44,8 @@ int CPU_HZ = 222000000;
namespace CoreTiming {
static std::vector<EventType> event_types;
// Far more than ever registered. Counts and ids from a savestate are checked against it.
static constexpr int MAX_EVENT_TYPES = 4096;
// Only used during restore.
static std::set<int> usedEventTypes;
static std::set<int> restoredEventTypes;
@@ -189,6 +191,9 @@ void RestoreRegisterEvent(int &event_type, const char *name, TimedCallback callb
// Some old states have a duplicate restore, do our best to fix...
if (restoredEventTypes.count(event_type) != 0)
event_type = -1;
// Straight from the file, so don't let a bogus id size the table.
if (event_type < -1 || event_type >= MAX_EVENT_TYPES)
event_type = -1;
if (event_type == -1)
event_type = nextEventTypeRestoreId++;
if (event_type >= (int)event_types.size()) {
@@ -542,6 +547,11 @@ void DoState(PointerWrap &p) {
int n = (int)event_types.size();
int current = n;
Do(p, n);
if (n < 0 || n > MAX_EVENT_TYPES) {
ERROR_LOG(Log::SaveState, "Savestate failure: implausible event type count %d", n);
p.SetError(p.ERROR_FAILURE);
return;
}
if (n > current) {
if (p.mode != PointerWrap::MODE_READ) {
WARN_LOG(Log::SaveState, "Savestate failure: more events than current");
@@ -579,6 +589,13 @@ void DoState(PointerWrap &p) {
}
Do(p, CPU_HZ);
if (CPU_HZ <= 0) {
// Everything divides by it.
ERROR_LOG(Log::SaveState, "Savestate failure: bad CPU frequency %d", (int)CPU_HZ);
p.SetError(p.ERROR_FAILURE);
CPU_HZ = 222000000;
return;
}
Do(p, slicelength);
Do(p, globalTimer);
Do(p, idledCycles);
+2 -1
View File
@@ -497,7 +497,8 @@ void HLEDoState(PointerWrap &p) {
delete action;
}
mipsCallActions.clear();
if (actions < 0) {
// Each action takes at least its type id.
if (actions < 0 || (size_t)actions > p.Remaining() / sizeof(int)) {
p.SetError(p.ERROR_FAILURE);
return;
}