On Fri, Oct 23, 2026 at 7:32 AM Stian Halseth <[email protected]> wrote: > In a serial context, tb_gen_code() flushes a full code buffer and > retries in place. cpu_exec_loop() then chains its last_tb, now freed, > into the new TB. When that TB is invalidated, tb_jmp_unlink() follows > the stale entry and qemu crashes inside its SIGSEGV handler. > > Drop last_tb when tb_gen_code() has flushed. > > User-only builds hit this easily since cross-page goto_tb chaining, > e.g. qemu-sparc64 -tb-size 1 on a program writing next to its PLT. > > Fixes: ebf7a5d294a3 ("accel/tcg: Improve buffer overflow in tb_gen_code") > Fixes: 25e5c6a320db ("accel/tcg: Allow cross-page goto_tb chaining in > user-only builds")
Thanks for tracking this down. I don't think the second Fixes tag is right. The stale chain comes from ebf7a5d294 alone: any last_tb that exited through an unpatched goto_tb slot gets chained after the flush, same page or not. Your x86_64 observation fits that. 25e5c6a320 makes it much easier to hit, which is worth saying in the commit message, but it didn't introduce the bug. I'd drop that tag. ebf7a5d294 has been in since v10.2.0, so this should go to stable: Cc: [email protected] > --- > 25e5c6a320db is not in a release yet (v11.1.x does not have it), so the > crash is new in the 11.2 cycle. The easy sparc64 reproducer is new, but tb_add_jump() writing into a freed and possibly reused TB is older than that. [...] > + /* tb_gen_code may have flushed, freeing last_tb. */ > + if (flush_count != qatomic_read(&tb_ctx.tb_flush_count)) { > + last_tb = NULL; > + } The fix itself looks right to me. The parallel case already leaves the loop through queue_tb_flush() and cpu_loop_exit(), so this is the only place that needs the check. With the Fixes tag fixed: Reviewed-by: Matt Turner <[email protected]> If you have a small reproducer that runs with -tb-size 1, a test under tests/tcg would be nice to have, but I wouldn't hold the patch for it.
