From 5cf009df8404130b66c104f8c3e0ca7757131b83 Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Wed, 7 Oct 2026 09:33:59 -0700 Subject: [PATCH] Preserve padded OT allocations with indexed late-packet relocation --- runtime/include/render_pass_ot_relocation.hpp | 12 +++++++++++- tests/test_render_pass_ot_relocation.cpp | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/runtime/include/render_pass_ot_relocation.hpp b/runtime/include/render_pass_ot_relocation.hpp index e2d54a75..841fc142 100644 --- a/runtime/include/render_pass_ot_relocation.hpp +++ b/runtime/include/render_pass_ot_relocation.hpp @@ -266,7 +266,17 @@ public: if((change.value&0x1fffffu)!=end)return refuse(__LINE__); splice_writes.push_back({change.address,(current_cursor&0xffe00000u)|new_end}); } else { - if(word(ram,change.address)!=word(after_core.data(),change.address))return refuse(__LINE__); + // The real tail's ordinary state updates are authoritative. + // Core replay can change temporary counters/bounds, so matching + // every RAM word against the original core rejects valid draw + // output. Only refuse a tail write that aliases CURRENT packet + // storage; the surrounding sandbox restores gameplay state. + const auto next=std::upper_bound(now.begin(),now.end(),change.address, + [](uint32_t address,const Node& node){return address>24)*4u)return refuse(__LINE__); + } splice_writes.push_back(change); } } diff --git a/tests/test_render_pass_ot_relocation.cpp b/tests/test_render_pass_ot_relocation.cpp index 889c0e88..f377a00c 100644 --- a/tests/test_render_pass_ot_relocation.cpp +++ b/tests/test_render_pass_ot_relocation.cpp @@ -98,8 +98,10 @@ int main() { put(ram,0x1310,0x02001300u); put(ram,0x1314,0x64000000);put(ram,0x1318,0x00100020); put(ram,OT,0x1310);put(ram,0x1800,0x80001320); + put(ram,0x1900,0x1234); // real tail advances an ordinary scratch counter CHECK(relocated.prepare(ram.data(),ram.size(),0x80001320)); ram=recorded_core;put(ram,0x1800,0x80001340); + put(ram,0x1900,0xabcd); // interpolation changed the temporary core value put(ram,0x1348,0x12345678);put(ram,0x134c,0x87654321); CHECK(relocated.prepare_splice(ram.data(),ram.size(),OT,0x80001340,0x1800)); relocated.apply_splice(ram.data()); @@ -108,6 +110,11 @@ int main() { CHECK(PSXOTRelocation::word(ram.data(),0x1348)==0x12345678); CHECK(PSXOTRelocation::word(ram.data(),0x134c)==0x87654321); CHECK(PSXOTRelocation::word(ram.data(),0x1800)==0x80001360); + CHECK(PSXOTRelocation::word(ram.data(),0x1900)==0x1234); + ram=recorded_core;put(ram,0x1800,0x80001340); + put(ram,OT,0x18fc);put(ram,0x18fc,0x02000000u|Core); + put(ram,0x1900,0x64000000);put(ram,0x1904,0x10002000); + CHECK(!relocated.prepare_splice(ram.data(),ram.size(),OT,0x80001340,0x1800)); ram=recorded_core;put(ram,0x1800,0x80001340); // A packet outside the actual producer interval is still refused. CHECK(relocated.prepare_splice(ram.data(),ram.size(),OT,0x801ffff0,0x1800)==false);