cpu-exec: Unlock tb_lock if we longjmp out of code generation

If the guest attempts to execute from unreadable memory, this will
cause us to longjmp back to the main loop from inside the
target frontend decoder. For linux-user mode, this means we will
still hold the tb_ctx.tb_lock, and will deadlock when we try to
start executing code again. Unlock the lock in the return-from-longjmp
code path to avoid this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Acked-by: Andrei Warkentin <andrey.warkentin@gmail.com>
Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Peter Maydell 2014-04-04 17:42:56 +01:00
parent cd7ccc8351
commit bae2c27090

View file

@ -227,6 +227,8 @@ int cpu_exec(CPUArchState *env)
TranslationBlock *tb;
uint8_t *tc_ptr;
uintptr_t next_tb;
/* This must be volatile so it is not trashed by longjmp() */
volatile bool have_tb_lock = false;
if (cpu->halted) {
if (!cpu_has_work(cpu)) {
@ -600,6 +602,7 @@ int cpu_exec(CPUArchState *env)
cpu_loop_exit(cpu);
}
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
have_tb_lock = true;
tb = tb_find_fast(env);
/* Note: we do it here to avoid a gcc bug on Mac OS X when
doing it in tb_find_slow */
@ -621,6 +624,7 @@ int cpu_exec(CPUArchState *env)
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
next_tb & TB_EXIT_MASK, tb);
}
have_tb_lock = false;
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
/* cpu_interrupt might be called while translating the
@ -692,6 +696,10 @@ int cpu_exec(CPUArchState *env)
#ifdef TARGET_I386
x86_cpu = X86_CPU(cpu);
#endif
if (have_tb_lock) {
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
have_tb_lock = false;
}
}
} /* for(;;) */