cpu-exec: fix icount out-of-bounds access

When icount is active, tb_add_jump is surprisingly called with an
out of bounds basic block index.  I have no idea how that can work,
but it does not seem like a good idea.  Clear *last_tb for all
TB_EXIT_ICOUNT_EXPIRED cases, even when all you have to do is
refill icount_extra.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2017-01-29 12:00:59 +01:00
parent d9ff1d35c5
commit 43d70ddf9f
2 changed files with 5 additions and 3 deletions

View File

@ -542,7 +542,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
trace_exec_tb(tb, tb->pc); trace_exec_tb(tb, tb->pc);
ret = cpu_tb_exec(cpu, tb); ret = cpu_tb_exec(cpu, tb);
*last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK); tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
*tb_exit = ret & TB_EXIT_MASK; *tb_exit = ret & TB_EXIT_MASK;
switch (*tb_exit) { switch (*tb_exit) {
case TB_EXIT_REQUESTED: case TB_EXIT_REQUESTED:
@ -566,6 +566,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
abort(); abort();
#else #else
int insns_left = cpu->icount_decr.u32; int insns_left = cpu->icount_decr.u32;
*last_tb = NULL;
if (cpu->icount_extra && insns_left >= 0) { if (cpu->icount_extra && insns_left >= 0) {
/* Refill decrementer and continue execution. */ /* Refill decrementer and continue execution. */
cpu->icount_extra += insns_left; cpu->icount_extra += insns_left;
@ -575,17 +576,17 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
} else { } else {
if (insns_left > 0) { if (insns_left > 0) {
/* Execute remaining instructions. */ /* Execute remaining instructions. */
cpu_exec_nocache(cpu, insns_left, *last_tb, false); cpu_exec_nocache(cpu, insns_left, tb, false);
align_clocks(sc, cpu); align_clocks(sc, cpu);
} }
cpu->exception_index = EXCP_INTERRUPT; cpu->exception_index = EXCP_INTERRUPT;
*last_tb = NULL;
cpu_loop_exit(cpu); cpu_loop_exit(cpu);
} }
break; break;
#endif #endif
} }
default: default:
*last_tb = tb;
break; break;
} }
} }

View File

@ -318,6 +318,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
static inline void tb_add_jump(TranslationBlock *tb, int n, static inline void tb_add_jump(TranslationBlock *tb, int n,
TranslationBlock *tb_next) TranslationBlock *tb_next)
{ {
assert(n < ARRAY_SIZE(tb->jmp_list_next));
if (tb->jmp_list_next[n]) { if (tb->jmp_list_next[n]) {
/* Another thread has already done this while we were /* Another thread has already done this while we were
* outside of the lock; nothing to do in this case */ * outside of the lock; nothing to do in this case */