unicorn
unicorn copied to clipboard
RISC-V64 incorrectly returns error when calling `emu_start` with `count` = 1 at end of page
When executing a single instruction at the end of a page with the following page unmapped, unicorn will return a memory error (FETCH_UNMAPPED
) instead of stopping.
This can be reproduced with:
// Cargo.toml
[package]
name = "minimal-unicorn-test"
version = "0.1.0"
edition = "2021"
[dependencies]
unicorn-engine = "2.0.1"
// src/main.rs
use unicorn_engine::{unicorn_const::{Arch, Mode, Permission}, RegisterRISCV, Unicorn};
fn main() {
let mut unicorn = Unicorn::new_with_data(Arch::RISCV, Mode::RISCV64, false)
.expect("failed to initialize Unicorn instance");
check(&mut unicorn, 0x6D76D7473FF0);
check(&mut unicorn, 0x6D76D7473FFC);
}
fn check(unicorn: &mut Unicorn<'_, bool>, addr: u64) {
unicorn.mem_map(addr & !0xfff, 4096, Permission::EXEC).unwrap();
unicorn.mem_write(addr, &[ 0x13, 0x81, 0x00, 0x7d ]).unwrap();
unicorn.reg_write(RegisterRISCV::PC, addr).unwrap();
unicorn.reg_write(RegisterRISCV::X1, 0x1234).unwrap();
let execution_result = unicorn.emu_start(addr, addr + 4, 0, 1);
assert_eq!(unicorn.reg_read(RegisterRISCV::PC), Ok(addr + 4));
assert_eq!(unicorn.reg_read(RegisterRISCV::X2), Ok(0x1234 + 2000));
assert_eq!(execution_result, Ok(()));
unicorn.mem_unmap(addr & !0xfff, 4096).unwrap();
println!("Execution at 0x{addr:X} OK");
}
Note how emu_start
is called with count
as 1
.
The first call to check
places the instruction 16 bytes from the end of the page. This is successfully executed. The second call to check
places the instruction exactly at the page edge. This fails with an error, but the resulting unicorn state is correct. Unicorn should return Ok(())
here instead of an error.