use std::env;
use std::io::{self, Read};
use std::os::raw::c_char;
use std::panic;
unsafe extern "C" {
fn __afl_persistent_loop(counter: usize) -> isize;
fn __afl_manual_init();
static __afl_fuzz_len: *const u32;
static __afl_fuzz_ptr: *const u8;
}
unsafe extern "C" {
pub fn ijon_max(addr: u32, val: u64);
pub fn ijon_min(addr: u32, val: u64);
pub fn ijon_set(addr: u32, val: u32);
pub fn ijon_inc(addr: u32, val: u32);
pub fn ijon_xor_state(val: u32);
pub fn ijon_reset_state();
pub fn ijon_simple_hash(x: u64) -> u64;
pub fn ijon_hashint(old: u32, val: u32) -> u32;
pub fn ijon_hashstr(old: u32, val: *const c_char) -> u32;
pub fn ijon_hashmen(old: u32, val: *const u8, len: usize) -> u32;
pub fn ijon_hashstack_backtrace() -> u32;
pub fn ijon_hashstack() -> u32;
pub fn ijon_strdist(a: *const u8, b: *const u8) -> u32;
pub fn ijon_memdist(a: *const u8, b: *const u8, len: usize) -> u32;
pub fn ijon_max_variadic(addr: u32, ...);
pub fn ijon_min_variadic(addr: u32, ...);
}
#[macro_export]
macro_rules! ijon_inc {
($x:expr) => {{
unsafe {
static mut loc: u32 = 0;
if loc == 0 {
let cfile = std::ffi::CString::new(file!()).unwrap();
loc = afl::ijon_hashstr(line!(), cfile.as_ptr());
}
afl::ijon_inc(loc, $x)
};
}};
}
#[macro_export]
macro_rules! ijon_max {
($($x:expr),+ $(,)?) => {{
unsafe {
static mut loc: u32 = 0;
if loc == 0 {
let cfile = std::ffi::CString::new(file!()).unwrap();
loc = afl::ijon_hashstr(line!(), cfile.as_ptr());
}
afl::ijon_max_variadic(_IJON_LOC_CACHE, $($x),+, 0u64)
};
}};
}
#[macro_export]
macro_rules! ijon_min {
($($x:expr),+ $(,)?) => {{
unsafe {
static mut loc: u32 = 0;
if loc == 0 {
let cfile = std::ffi::CString::new(file!()).unwrap();
loc = afl::ijon_hashstr(line!(), cfile.as_ptr());
}
afl::ijon_min_variadic(loc, $($x),+, 0u64)
};
}};
}
#[macro_export]
macro_rules! ijon_set {
($x:expr) => {{
unsafe {
static mut loc: u32 = 0;
if loc == 0 {
let cfile = std::ffi::CString::new(file!()).unwrap();
loc = afl::ijon_hashstr(line!(), cfile.as_ptr());
}
afl::ijon_set(loc, $x)
};
}};
}
#[macro_export]
macro_rules! ijon_state {
($n:expr) => {
unsafe { afl::ijon_xor_state($n) }
};
}
#[macro_export]
macro_rules! ijon_ctx {
($x:expr) => {{
let cfile = std::ffi::CString::new(file!()).unwrap();
let hash = unsafe { afl::ijon_hashstr(line!(), cfile.as_ptr()) };
unsafe { afl::ijon_xor_state(hash) };
let temp = $x;
unsafe { afl::ijon_xor_state(hash) };
temp
}};
}
#[macro_export]
macro_rules! ijon_max_at {
($addr:expr, $x:expr) => {
unsafe { afl::ijon_max($addr, $x) }
};
}
#[macro_export]
macro_rules! ijon_min_at {
($addr:expr, $x:expr) => {
unsafe { afl::ijon_min($addr, $x) }
};
}
#[macro_export]
macro_rules! _ijon_abs_dist {
($x:expr, $y:expr) => {
if $x < $y { $y - $x } else { $x - $y }
};
}
#[macro_export]
macro_rules! ijon_bits {
($x:expr) => {
unsafe {
afl::ijon_set(afl::ijon_hashint(
afl::ijon_hashstack(),
if $x == 0 {
0
} else {
$x.leading_zeros() as u32
},
))
}
};
}
#[macro_export]
macro_rules! ijon_strdist {
($x:expr, $y:expr) => {
unsafe {
afl::ijon_set(afl::ijon_hashint(
afl::ijon_hashstack(),
afl::ijon_strdist($x, $y),
))
}
};
}
#[macro_export]
macro_rules! ijon_dist {
($x:expr, $y:expr) => {
unsafe {
afl::ijon_set(afl::ijon_hashint(
afl::ijon_hashstack(),
$crate::_ijon_abs_dist!($x, $y),
))
}
};
}
#[macro_export]
macro_rules! ijon_cmp {
($x:expr, $y:expr) => {
unsafe {
afl::ijon_inc(afl::ijon_hashint(
afl::ijon_hashstack(),
($x ^ $y).count_ones(),
))
}
};
}
#[macro_export]
macro_rules! ijon_stack_max {
($x:expr) => {{
unsafe {
static mut loc: u32 = 0;
if loc == 0 {
let cfile = std::ffi::CString::new(file!()).unwrap();
loc = afl::ijon_hashstr(line!(), cfile.as_ptr());
}
afl::ijon_max(afl::ijon_hashint(loc, afl::ijon_hashstack()), $x)
};
}};
}
#[macro_export]
macro_rules! ijon_stack_min {
($x:expr) => {{
unsafe {
static mut loc: u32 = 0;
if loc == 0 {
let cfile = std::ffi::CString::new(file!()).unwrap();
loc = afl::ijon_hashstr(line!(), cfile.as_ptr());
}
afl::ijon_min(afl::ijon_hashint(loc, afl::ijon_hashstack()), $x)
};
}};
}
#[allow(non_upper_case_globals)]
#[doc(hidden)]
#[unsafe(no_mangle)]
pub static mut __afl_sharedmem_fuzzing: i32 = 1;
pub fn fuzz<F>(hook: bool, mut closure: F)
where
F: FnMut(&[u8]) + std::panic::RefUnwindSafe,
{
static PERSIST_MARKER: &str = "##SIG_AFL_PERSISTENT##\0";
static DEFERED_MARKER: &str = "##SIG_AFL_DEFER_FORKSRV##\0";
unsafe { std::ptr::read_volatile(&raw const PERSIST_MARKER) }; unsafe { std::ptr::read_volatile(&raw const DEFERED_MARKER) };
if hook {
let prev_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
prev_hook(panic_info);
std::process::abort();
}));
}
let mut input = vec![];
let loop_count = if let Ok(value) = env::var("AFL_FUZZER_LOOPCOUNT") {
value
.parse()
.expect("Failed to parse environment variable to a number")
} else {
usize::MAX
};
unsafe { __afl_manual_init() };
while unsafe { __afl_persistent_loop(loop_count) } != 0 {
let input_ref = if unsafe { __afl_fuzz_ptr.is_null() } {
let result = io::stdin().read_to_end(&mut input);
if result.is_err() {
return;
}
&input
} else {
unsafe {
let input_len = *__afl_fuzz_len as usize;
std::slice::from_raw_parts(__afl_fuzz_ptr, input_len)
}
};
let did_panic = std::panic::catch_unwind(panic::AssertUnwindSafe(|| {
closure(input_ref);
}))
.is_err();
if did_panic {
std::process::abort();
}
input.clear();
}
}
#[macro_export]
macro_rules! fuzz {
( $($x:tt)* ) => { $crate::__fuzz!(true, $($x)*) }
}
#[macro_export]
macro_rules! fuzz_nohook {
( $($x:tt)* ) => { $crate::__fuzz!(false, $($x)*) }
}
#[doc(hidden)]
#[macro_export]
macro_rules! __fuzz {
($hook:expr, |$buf:ident| $body:expr) => {
$crate::fuzz($hook, |$buf| $body);
};
($hook:expr, |$buf:ident: &[u8]| $body:expr) => {
$crate::fuzz($hook, |$buf| $body);
};
($hook:expr, |$buf:ident: $dty: ty| $body:expr) => {
$crate::fuzz($hook, |$buf| {
let $buf: $dty = {
let mut data = ::arbitrary::Unstructured::new($buf);
if let Ok(d) = ::arbitrary::Arbitrary::arbitrary(&mut data).map_err(|_| "") {
d
} else {
return;
}
};
$body
});
};
}