Fix opt_diff
This commit is contained in:
parent
2ff4d80286
commit
ac2556a7ad
|
@ -23,7 +23,13 @@ fuzz_target!(
|
||||||
|
|
||||||
let start = parsed_module.start_func.unwrap();
|
let start = parsed_module.start_func.unwrap();
|
||||||
|
|
||||||
let mut orig_ctx = InterpContext::new(&parsed_module);
|
let mut orig_ctx = match InterpContext::new(&parsed_module) {
|
||||||
|
Ok(ctx) => ctx,
|
||||||
|
Err(e) => {
|
||||||
|
log::trace!("Rejecting due to instantiation error: {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
orig_ctx.fuel = 10000;
|
orig_ctx.fuel = 10000;
|
||||||
|
|
||||||
match orig_ctx.call(&parsed_module, start, &[]) {
|
match orig_ctx.call(&parsed_module, start, &[]) {
|
||||||
|
@ -32,6 +38,11 @@ fuzz_target!(
|
||||||
log::trace!("Rejecting due to timeout in orig");
|
log::trace!("Rejecting due to timeout in orig");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
InterpResult::Trap => {
|
||||||
|
// Silently reject.
|
||||||
|
log::trace!("Rejecting due to trap in orig");
|
||||||
|
return;
|
||||||
|
}
|
||||||
InterpResult::Ok(_) => {}
|
InterpResult::Ok(_) => {}
|
||||||
ret => panic!("Bad result: {:?}", ret),
|
ret => panic!("Bad result: {:?}", ret),
|
||||||
}
|
}
|
||||||
|
@ -39,7 +50,7 @@ fuzz_target!(
|
||||||
let mut opt_module = parsed_module.clone();
|
let mut opt_module = parsed_module.clone();
|
||||||
opt_module.per_func_body(|body| body.optimize());
|
opt_module.per_func_body(|body| body.optimize());
|
||||||
|
|
||||||
let mut opt_ctx = InterpContext::new(&opt_module);
|
let mut opt_ctx = InterpContext::new(&opt_module).unwrap();
|
||||||
// Allow a little leeway for opts to not actually optimize.
|
// Allow a little leeway for opts to not actually optimize.
|
||||||
opt_ctx.fuel = 20000;
|
opt_ctx.fuel = 20000;
|
||||||
opt_ctx.call(&opt_module, start, &[]).ok().unwrap();
|
opt_ctx.call(&opt_module, start, &[]).ok().unwrap();
|
||||||
|
|
|
@ -101,7 +101,7 @@ fn main() -> Result<()> {
|
||||||
// Ensure all functions are expanded -- this is necessary
|
// Ensure all functions are expanded -- this is necessary
|
||||||
// for interpretation.
|
// for interpretation.
|
||||||
module.expand_all_funcs()?;
|
module.expand_all_funcs()?;
|
||||||
let mut ctx = InterpContext::new(&module);
|
let mut ctx = InterpContext::new(&module)?;
|
||||||
debug!("Calling start function");
|
debug!("Calling start function");
|
||||||
if let Some(start) = module.start_func {
|
if let Some(start) = module.start_func {
|
||||||
ctx.call(&module, start, &[]).ok().unwrap();
|
ctx.call(&module, start, &[]).ok().unwrap();
|
||||||
|
|
254
src/interp.rs
254
src/interp.rs
|
@ -37,7 +37,7 @@ impl InterpResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InterpContext {
|
impl InterpContext {
|
||||||
pub fn new(module: &Module<'_>) -> Self {
|
pub fn new(module: &Module<'_>) -> anyhow::Result<Self> {
|
||||||
let mut memories = PerEntity::default();
|
let mut memories = PerEntity::default();
|
||||||
for (memory, data) in module.memories.entries() {
|
for (memory, data) in module.memories.entries() {
|
||||||
let mut interp_mem = InterpMemory {
|
let mut interp_mem = InterpMemory {
|
||||||
|
@ -45,8 +45,14 @@ impl InterpContext {
|
||||||
max_pages: data.maximum_pages.unwrap_or(0x1_0000),
|
max_pages: data.maximum_pages.unwrap_or(0x1_0000),
|
||||||
};
|
};
|
||||||
for segment in &data.segments {
|
for segment in &data.segments {
|
||||||
interp_mem.data[segment.offset..(segment.offset + segment.data.len())]
|
let end = match segment.offset.checked_add(segment.data.len()) {
|
||||||
.copy_from_slice(&segment.data[..]);
|
Some(end) => end,
|
||||||
|
None => anyhow::bail!("Data segment offset + length overflows"),
|
||||||
|
};
|
||||||
|
if end > interp_mem.data.len() {
|
||||||
|
anyhow::bail!("Data segment out of bounds");
|
||||||
|
}
|
||||||
|
interp_mem.data[segment.offset..end].copy_from_slice(&segment.data[..]);
|
||||||
}
|
}
|
||||||
memories[memory] = interp_mem;
|
memories[memory] = interp_mem;
|
||||||
}
|
}
|
||||||
|
@ -70,12 +76,12 @@ impl InterpContext {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
InterpContext {
|
Ok(InterpContext {
|
||||||
memories,
|
memories,
|
||||||
tables,
|
tables,
|
||||||
globals,
|
globals,
|
||||||
fuel: u64::MAX,
|
fuel: u64::MAX,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(&mut self, module: &Module<'_>, func: Func, args: &[ConstVal]) -> InterpResult {
|
pub fn call(&mut self, module: &Module<'_>, func: Func, args: &[ConstVal]) -> InterpResult {
|
||||||
|
@ -939,125 +945,217 @@ pub fn const_eval(
|
||||||
(Operator::Nop, []) => Some(ConstVal::None),
|
(Operator::Nop, []) => Some(ConstVal::None),
|
||||||
(Operator::Unreachable, []) => None,
|
(Operator::Unreachable, []) => None,
|
||||||
|
|
||||||
(Operator::I32Load { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I32Load { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I32(read_u32(&global.memories[memory.memory], addr))
|
if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I32(read_u32(
|
||||||
|
&global.memories[memory.memory],
|
||||||
|
addr,
|
||||||
|
)))
|
||||||
}),
|
}),
|
||||||
(Operator::I64Load { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I64Load { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I64(read_u64(&global.memories[memory.memory], addr))
|
if addr.checked_add(8)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I64(read_u64(
|
||||||
|
&global.memories[memory.memory],
|
||||||
|
addr,
|
||||||
|
)))
|
||||||
}),
|
}),
|
||||||
(Operator::F32Load { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::F32Load { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::F32(read_u32(&global.memories[memory.memory], addr))
|
if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::F32(read_u32(
|
||||||
|
&global.memories[memory.memory],
|
||||||
|
addr,
|
||||||
|
)))
|
||||||
}),
|
}),
|
||||||
(Operator::F64Load { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::F64Load { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::F64(read_u64(&global.memories[memory.memory], addr))
|
if addr.checked_add(8)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::F64(read_u64(
|
||||||
|
&global.memories[memory.memory],
|
||||||
|
addr,
|
||||||
|
)))
|
||||||
}),
|
}),
|
||||||
(Operator::I32Load8S { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I32Load8S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I32(read_u8(&global.memories[memory.memory], addr) as i8 as i32 as u32)
|
if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I32(
|
||||||
|
read_u8(&global.memories[memory.memory], addr) as i8 as i32 as u32,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I32Load8U { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I32Load8U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I32(read_u8(&global.memories[memory.memory], addr) as u32)
|
if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I32(
|
||||||
|
read_u8(&global.memories[memory.memory], addr) as u32,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I32Load16S { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I32Load16S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I32(read_u16(&global.memories[memory.memory], addr) as i16 as i32 as u32)
|
if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I32(
|
||||||
|
read_u16(&global.memories[memory.memory], addr) as i16 as i32 as u32,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I32Load16U { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I32Load16U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I32(read_u16(&global.memories[memory.memory], addr) as u32)
|
if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I32(
|
||||||
|
read_u16(&global.memories[memory.memory], addr) as u32,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I64Load8S { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I64Load8S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I64(read_u8(&global.memories[memory.memory], addr) as i8 as i64 as u64)
|
if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I64(
|
||||||
|
read_u8(&global.memories[memory.memory], addr) as i8 as i64 as u64,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I64Load8U { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I64Load8U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I64(read_u8(&global.memories[memory.memory], addr) as u64)
|
if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I64(
|
||||||
|
read_u8(&global.memories[memory.memory], addr) as u64,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I64Load16S { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I64Load16S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I64(read_u16(&global.memories[memory.memory], addr) as i16 as i64 as u64)
|
if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I64(
|
||||||
|
read_u16(&global.memories[memory.memory], addr) as i16 as i64 as u64,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I64Load16U { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I64Load16U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I64(read_u16(&global.memories[memory.memory], addr) as u64)
|
if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I64(
|
||||||
|
read_u16(&global.memories[memory.memory], addr) as u64,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I64Load32S { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I64Load32S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I64(read_u32(&global.memories[memory.memory], addr) as i32 as i64 as u64)
|
if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I64(
|
||||||
|
read_u32(&global.memories[memory.memory], addr) as i32 as i64 as u64,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I64Load32U { memory }, [ConstVal::I32(addr)]) => ctx.map(|global| {
|
(Operator::I64Load32U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
ConstVal::I64(read_u32(&global.memories[memory.memory], addr) as u64)
|
if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ConstVal::I64(
|
||||||
|
read_u32(&global.memories[memory.memory], addr) as u64,
|
||||||
|
))
|
||||||
}),
|
}),
|
||||||
(Operator::I32Store { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => {
|
(Operator::I32Store { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => ctx
|
||||||
ctx.map(|global| {
|
.and_then(|global| {
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
|
if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
write_u32(&mut global.memories[memory.memory], addr, *data);
|
write_u32(&mut global.memories[memory.memory], addr, *data);
|
||||||
ConstVal::None
|
Some(ConstVal::None)
|
||||||
})
|
}),
|
||||||
}
|
(Operator::I64Store { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => ctx
|
||||||
(Operator::I64Store { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => {
|
.and_then(|global| {
|
||||||
ctx.map(|global| {
|
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
|
if addr.checked_add(8)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
write_u64(&mut global.memories[memory.memory], addr, *data);
|
write_u64(&mut global.memories[memory.memory], addr, *data);
|
||||||
ConstVal::None
|
Some(ConstVal::None)
|
||||||
})
|
}),
|
||||||
}
|
(Operator::I32Store8 { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => ctx
|
||||||
(Operator::I32Store8 { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => {
|
.and_then(|global| {
|
||||||
ctx.map(|global| {
|
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
|
if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
write_u8(&mut global.memories[memory.memory], addr, *data as u8);
|
write_u8(&mut global.memories[memory.memory], addr, *data as u8);
|
||||||
ConstVal::None
|
Some(ConstVal::None)
|
||||||
})
|
}),
|
||||||
}
|
(Operator::I32Store16 { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => ctx
|
||||||
(Operator::I32Store16 { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => {
|
.and_then(|global| {
|
||||||
ctx.map(|global| {
|
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
|
if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
write_u16(&mut global.memories[memory.memory], addr, *data as u16);
|
write_u16(&mut global.memories[memory.memory], addr, *data as u16);
|
||||||
ConstVal::None
|
Some(ConstVal::None)
|
||||||
})
|
}),
|
||||||
}
|
(Operator::I64Store8 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => ctx
|
||||||
(Operator::I64Store8 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => {
|
.and_then(|global| {
|
||||||
ctx.map(|global| {
|
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
|
if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
write_u8(&mut global.memories[memory.memory], addr, *data as u8);
|
write_u8(&mut global.memories[memory.memory], addr, *data as u8);
|
||||||
ConstVal::None
|
Some(ConstVal::None)
|
||||||
})
|
}),
|
||||||
}
|
(Operator::I64Store16 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => ctx
|
||||||
(Operator::I64Store16 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => {
|
.and_then(|global| {
|
||||||
ctx.map(|global| {
|
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
|
if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
write_u16(&mut global.memories[memory.memory], addr, *data as u16);
|
write_u16(&mut global.memories[memory.memory], addr, *data as u16);
|
||||||
ConstVal::None
|
Some(ConstVal::None)
|
||||||
})
|
}),
|
||||||
}
|
(Operator::I64Store32 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => ctx
|
||||||
(Operator::I64Store32 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => {
|
.and_then(|global| {
|
||||||
ctx.map(|global| {
|
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
|
if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
write_u32(&mut global.memories[memory.memory], addr, *data as u32);
|
write_u32(&mut global.memories[memory.memory], addr, *data as u32);
|
||||||
ConstVal::None
|
Some(ConstVal::None)
|
||||||
})
|
}),
|
||||||
}
|
(Operator::F32Store { memory }, [ConstVal::I32(addr), ConstVal::F32(data)]) => ctx
|
||||||
(Operator::F32Store { memory }, [ConstVal::I32(addr), ConstVal::F32(data)]) => {
|
.and_then(|global| {
|
||||||
ctx.map(|global| {
|
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
|
if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
write_u32(&mut global.memories[memory.memory], addr, *data);
|
write_u32(&mut global.memories[memory.memory], addr, *data);
|
||||||
ConstVal::None
|
Some(ConstVal::None)
|
||||||
})
|
}),
|
||||||
}
|
(Operator::F64Store { memory }, [ConstVal::I32(addr), ConstVal::F64(data)]) => ctx
|
||||||
(Operator::F64Store { memory }, [ConstVal::I32(addr), ConstVal::F64(data)]) => {
|
.and_then(|global| {
|
||||||
ctx.map(|global| {
|
|
||||||
let addr = *addr + memory.offset;
|
let addr = *addr + memory.offset;
|
||||||
write_u64(&mut global.memories[memory.memory], addr, *data);
|
if addr.checked_add(8)? > global.memories[memory.memory].data.len() as u32 {
|
||||||
ConstVal::None
|
return None;
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
write_u64(&mut global.memories[memory.memory], addr, *data);
|
||||||
|
Some(ConstVal::None)
|
||||||
|
}),
|
||||||
(_, args) if args.iter().any(|&arg| arg == ConstVal::None) => None,
|
(_, args) if args.iter().any(|&arg| arg == ConstVal::None) => None,
|
||||||
(op, args) => unimplemented!(
|
(op, args) => unimplemented!(
|
||||||
"Undefined operator or arg combination: {:?}, {:?}",
|
"Undefined operator or arg combination: {:?}, {:?}",
|
||||||
|
|
Loading…
Reference in a new issue