Savestate: Fix action and exit callback handling on load

Delete the old HLE mips call actions instead of leaking them or keeping
stale ones, fail the load on an unknown action type instead of crashing,
and derive the exit-callback-pending flag from the loaded state.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-09-28 09:34:06 -06:00
1 parent 06e11fb176
commit 490f08d220
2 files changed
+34 -3

No files matched your search

+17 -3
View File
@@ -486,16 +486,30 @@ void HLEDoState(PointerWrap &p) {
if (s >= 2) {
int actions = (int)mipsCallActions.size();
Do(p, actions);
if (actions != (int)mipsCallActions.size()) {
mipsCallActions.resize(actions);
if (p.mode == p.MODE_READ) {
for (PSPAction *action : mipsCallActions) {
delete action;
}
mipsCallActions.clear();
if (actions < 0) {
p.SetError(p.ERROR_FAILURE);
return;
}
mipsCallActions.resize(actions, nullptr);
}
for (auto &action : mipsCallActions) {
int actionTypeID = action != nullptr ? action->actionTypeID : -1;
Do(p, actionTypeID);
if (actionTypeID != -1) {
if (p.mode == p.MODE_READ)
if (p.mode == p.MODE_READ) {
action = __KernelCreateAction(actionTypeID);
if (!action) {
ERROR_LOG(Log::SaveState, "Unable to load state: unknown action type %d", actionTypeID);
p.SetError(p.ERROR_FAILURE);
return;
}
}
action->DoState(p);
}
}
+17
View File
@@ -223,6 +223,10 @@ public:
{
if (p.mode == p.MODE_READ)
chainedAction = __KernelCreateAction(chainedActionType);
if (!chainedAction) {
p.SetError(p.ERROR_FAILURE);
return;
}
chainedAction->DoState(p);
}
}
@@ -286,6 +290,10 @@ public:
auto s = p.Section("ActionAfterExitCallback", 1);
if (!s)
return;
if (p.mode == p.MODE_READ) {
// The dispatch is still in flight in the loaded state (see __KernelThreadingDoState.)
g_exitCallbackPending = true;
}
}
};
@@ -570,6 +578,10 @@ void MipsCall::DoState(PointerWrap &p)
{
if (p.mode == p.MODE_READ)
doAfter = __KernelCreateAction(actionTypeID);
if (!doAfter) {
p.SetError(p.ERROR_FAILURE);
return;
}
doAfter->DoState(p);
}
}
@@ -810,6 +822,11 @@ void __KernelThreadingInit() {
void __KernelThreadingDoState(PointerWrap &p)
{
if (p.mode == p.MODE_READ) {
// Set again if an ActionAfterExitCallback is loaded (with the mips calls, later.)
g_exitCallbackPending = false;
}
auto s = p.Section("sceKernelThread", 1, 5);
if (!s)
return;