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:
parent
d9ff1d35c5
commit
43d70ddf9f
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user