diff --git a/runtime/src/memory.c b/runtime/src/memory.c index 4d82bbdc..6a438311 100644 --- a/runtime/src/memory.c +++ b/runtime/src/memory.c @@ -482,15 +482,19 @@ int dirty_ram_text_native_ok(uint32_t phys) { * a mismatch never poisons an unrelated 4 KB page forever: every decision is * made from the live bytes the native body will actually execute. * - * exec_pc is the dispatch/resume address. Ranges that end at or before that PC - * are skipped, and a range that straddles it is clipped to [exec_pc, end). A - * runtime patch of a function prologue must not block a compiled continuation - * that never fetches the patched bytes. */ + * exec_pc is the dispatch/resume address, kept for observability and future + * use; ranges are validated IN FULL regardless of it. The former + * [exec_pc, end) clip assumed a continuation "never fetches the patched + * bytes" behind its resume PC — false for any entry with a backward edge: + * a post-call continuation re-enters mid-function and loops back into the + * clipped-away region, executing stale static code (CMR2 overlay + * corruption, second locus 0x80016B34). A genuinely patched prologue now + * blocks the whole entry to the interpreter — correct, merely slower. */ int dirty_ram_text_native_ok_ranges_from(const uint32_t *lo_len_pairs, uint32_t count, uint32_t exec_pc) { if (!text_ref_image || !lo_len_pairs || count == 0) return 0; - uint32_t at = exec_pc & 0x1FFFFFFFu; + (void)exec_pc; int any = 0; for (uint32_t i = 0; i < count; i++) { uint32_t phys = lo_len_pairs[i * 2u] & 0x1FFFFFFFu; @@ -500,11 +504,6 @@ int dirty_ram_text_native_ok_ranges_from(const uint32_t *lo_len_pairs, g_text_native_blocked++; return 0; } - if (phys + len <= at) continue; - if (phys < at) { - len -= at - phys; - phys = at; - } any = 1; /* Page-clean fast path: every page this range touches is neither * guard-modified nor runtime-dirty, so its bytes still equal the