fuzz_thumb: Off by one error

This commit is contained in:
MerryMage 2018-01-14 20:21:47 +00:00
parent ecebe14a01
commit c34639f33d

View file

@ -80,6 +80,8 @@ static u16 MemoryRead16(u32 vaddr) {
static u32 MemoryRead32(u32 vaddr) { static u32 MemoryRead32(u32 vaddr) {
if (vaddr < code_mem.size() * sizeof(u16)) { if (vaddr < code_mem.size() * sizeof(u16)) {
size_t index = vaddr / sizeof(u16); size_t index = vaddr / sizeof(u16);
if (index + 1 >= code_mem.size())
return code_mem[index];
return code_mem[index] | (code_mem[index+1] << 16); return code_mem[index] | (code_mem[index+1] << 16);
} }
return vaddr; return vaddr;
@ -90,6 +92,8 @@ static u64 MemoryRead64(u32 vaddr) {
static u32 MemoryReadCode(u32 vaddr) { static u32 MemoryReadCode(u32 vaddr) {
if (vaddr < code_mem.size() * sizeof(u16)) { if (vaddr < code_mem.size() * sizeof(u16)) {
size_t index = vaddr / sizeof(u16); size_t index = vaddr / sizeof(u16);
if (index + 1 >= code_mem.size())
return code_mem[index];
return code_mem[index] | (code_mem[index + 1] << 16); return code_mem[index] | (code_mem[index + 1] << 16);
} }
return 0xE7FEE7FE; // b +#0, b +#0 return 0xE7FEE7FE; // b +#0, b +#0
@ -198,33 +202,18 @@ static bool DoesBehaviorMatch(const ARMul_State& interp, const Dynarmic::A32::Ji
&& interp_write_records == jit_write_records; && interp_write_records == jit_write_records;
} }
void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_execute_count, const size_t run_count, const std::function<u16()> instruction_generator) { static void RunInstance(size_t run_number, ARMul_State& interp, Dynarmic::A32::Jit& jit, const std::array<u32, 16>& initial_regs, size_t instruction_count, size_t instructions_to_execute_count) {
// Prepare memory
code_mem.fill(0xE7FE); // b +#0
// Prepare test subjects
ARMul_State interp{USER32MODE};
interp.user_callbacks = GetUserCallbacks();
Dynarmic::A32::Jit jit{GetUserCallbacks()};
for (size_t run_number = 0; run_number < run_count; run_number++) {
interp.instruction_cache.clear(); interp.instruction_cache.clear();
InterpreterClearCache(); InterpreterClearCache();
jit.ClearCache(); jit.ClearCache();
// Setup initial state // Setup initial state
std::array<u32, 16> initial_regs;
std::generate_n(initial_regs.begin(), 15, []{ return RandInt<u32>(0, 0xFFFFFFFF); });
initial_regs[15] = 0;
interp.Cpsr = 0x000001F0; interp.Cpsr = 0x000001F0;
interp.Reg = initial_regs; interp.Reg = initial_regs;
jit.SetCpsr(0x000001F0); jit.SetCpsr(0x000001F0);
jit.Regs() = initial_regs; jit.Regs() = initial_regs;
std::generate_n(code_mem.begin(), instruction_count, instruction_generator);
// Run interpreter // Run interpreter
write_records.clear(); write_records.clear();
interp.NumInstrsToExecute = static_cast<unsigned>(instructions_to_execute_count); interp.NumInstrsToExecute = static_cast<unsigned>(instructions_to_execute_count);
@ -247,7 +236,7 @@ void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_e
printf("\nInstruction Listing: \n"); printf("\nInstruction Listing: \n");
for (size_t i = 0; i < instruction_count; i++) { for (size_t i = 0; i < instruction_count; i++) {
printf("%s\n", Dynarmic::A32::DisassembleThumb16(code_mem[i]).c_str()); printf("%04x %s\n", code_mem[i], Dynarmic::A32::DisassembleThumb16(code_mem[i]).c_str());
} }
printf("\nInitial Register Listing: \n"); printf("\nInitial Register Listing: \n");
@ -295,8 +284,25 @@ void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_e
#endif #endif
FAIL(); FAIL();
} }
}
if (run_number % 10 == 0) printf("%zu\r", run_number); void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_execute_count, const size_t run_count, const std::function<u16()> instruction_generator) {
// Prepare memory
code_mem.fill(0xE7FE); // b +#0
// Prepare test subjects
ARMul_State interp{USER32MODE};
interp.user_callbacks = GetUserCallbacks();
Dynarmic::A32::Jit jit{GetUserCallbacks()};
for (size_t run_number = 0; run_number < run_count; run_number++) {
std::array<u32, 16> initial_regs;
std::generate_n(initial_regs.begin(), 15, []{ return RandInt<u32>(0, 0xFFFFFFFF); });
initial_regs[15] = 0;
std::generate_n(code_mem.begin(), instruction_count, instruction_generator);
RunInstance(run_number, interp, jit, initial_regs, instruction_count, instructions_to_execute_count);
} }
} }
@ -380,3 +386,40 @@ TEST_CASE("Fuzz Thumb instructions set 2 (affects PC)", "[JitX64][Thumb]") {
FuzzJitThumb(1, 1, 10000, instruction_select); FuzzJitThumb(1, 1, 10000, instruction_select);
} }
TEST_CASE("Verify fix for off by one error in MemoryRead32 worked", "[Thumb]") {
// Prepare memory
code_mem.fill(0xE7FE); // b +#0
// Prepare test subjects
ARMul_State interp{USER32MODE};
interp.user_callbacks = GetUserCallbacks();
Dynarmic::A32::Jit jit{GetUserCallbacks()};
std::array<u32, 16> initial_regs {
0xe90ecd70,
0x3e3b73c3,
0x571616f9,
0x0b1ef45a,
0xb3a829f2,
0x915a7a6a,
0x579c38f4,
0xd9ffe391,
0x55b6682b,
0x458d8f37,
0x8f3eb3dc,
0xe18c0e7d,
0x6752657a,
0x00001766,
0xdbbf23e3,
0x00000000,
};
code_mem[0] = 0x40B8; // lsls r0, r7, #0
code_mem[1] = 0x01CA; // lsls r2, r1, #7
code_mem[2] = 0x83A1; // strh r1, [r4, #28]
code_mem[3] = 0x708A; // strb r2, [r1, #2]
code_mem[4] = 0xBCC4; // pop {r2, r6, r7}
RunInstance(1, interp, jit, initial_regs, 5, 5);
}