diff --git a/runtime/src/debug_server.c b/runtime/src/debug_server.c index 27b495ea..6796c5cb 100644 --- a/runtime/src/debug_server.c +++ b/runtime/src/debug_server.c @@ -19,6 +19,7 @@ #include "debug_server.h" #include "host_launch_timing.h" #include "host_sampler.h" +#include "savestate.h" #include "guest_cycle_profile.h" #include "host_osd.h" #include "psx_video_timing.h" @@ -9472,6 +9473,12 @@ static void handle_savestate(int id, const char *json) extern int psx_netplay_request_load(int slot); int slot = json_get_int(json, "slot", -1); if (slot < 0) { send_err(id, "missing slot"); return; } + if (slot >= SAVESTATE_SLOTS) { + /* Name the real reason: the generic refusal below blamed LLE runs. */ + send_fmt("{\"id\":%d,\"ok\":false,\"error\":\"slot %d out of range (0..%d)\"}", + id, slot, SAVESTATE_SLOTS - 1); + return; + } char op[16]; if (!json_get_str(json, "op", op, sizeof(op))) { send_err(id, "missing op"); return; } int staged; diff --git a/runtime/tests/test_savestate_status_protocol.py b/runtime/tests/test_savestate_status_protocol.py index 6191e37d..9a515a2e 100644 --- a/runtime/tests/test_savestate_status_protocol.py +++ b/runtime/tests/test_savestate_status_protocol.py @@ -46,3 +46,10 @@ assert "(resume_pc == 0u && !pc_matches_cpu) || !snapshot_safe || !pc_ok" in STA assert "!psx_irq_resume_context_snapshot_safe_at(pc) || !resume_pc_ok(pc)" in REWIND assert "psx_check_interrupts_at(cpu, pc)" in DIRTY print("savestate status protocol guard passed") + +# The debug server names an out-of-range slot instead of the generic refusal. +_handler = SERVER[SERVER.index("static void handle_savestate(int id"):] +_handler = _handler[:_handler.index("\n}\n")] +assert "slot >= SAVESTATE_SLOTS" in _handler +assert _handler.index("slot >= SAVESTATE_SLOTS") < _handler.index("savestate_request_save(slot)") +assert "out of range (0..%d)" in _handler