Skip to content

Commit

Permalink
As part of our non-trapping logic for load operations, we emit instru…
Browse files Browse the repository at this point in the history
…ctions

that must check if the memory offset plus the size of the type is within the bounds
of our memory. In order for us to emit this code, that value must fit in a u64.
In the case where the memory offset is u64::MAX, then our rust code panics in trying
to generate the wasm due to an attempt to add with overflow. To solve this, I've added
an upper bound on our memory offsets for load operations while running in non-trapping
mode.
  • Loading branch information
itsrainy committed Oct 27, 2022
1 parent 4fda694 commit d091301
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 15 deletions.
42 changes: 28 additions & 14 deletions crates/wasm-smith/src/core/code_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1877,9 +1877,10 @@ fn i64_load(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1, 2, 3])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1, 2, 3])?;
builder.allocs.operands.push(Some(ValType::I64));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 8);
no_traps::load(Instruction::I64Load(memarg), module, builder, instructions);
} else {
instructions.push(Instruction::I64Load(memarg));
Expand All @@ -1893,9 +1894,10 @@ fn f32_load(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1, 2])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1, 2])?;
builder.allocs.operands.push(Some(ValType::F32));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 4);
no_traps::load(Instruction::F32Load(memarg), module, builder, instructions);
} else {
instructions.push(Instruction::F32Load(memarg));
Expand All @@ -1909,9 +1911,10 @@ fn f64_load(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1, 2, 3])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1, 2, 3])?;
builder.allocs.operands.push(Some(ValType::F64));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 8);
no_traps::load(Instruction::F64Load(memarg), module, builder, instructions);
} else {
instructions.push(Instruction::F64Load(memarg));
Expand All @@ -1925,9 +1928,10 @@ fn i32_load_8_s(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0])?;
let mut memarg = mem_arg(u, module, builder, &[0])?;
builder.allocs.operands.push(Some(ValType::I32));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 4);
no_traps::load(
Instruction::I32Load8S(memarg),
module,
Expand All @@ -1946,9 +1950,10 @@ fn i32_load_8_u(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0])?;
let mut memarg = mem_arg(u, module, builder, &[0])?;
builder.allocs.operands.push(Some(ValType::I32));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 4);
no_traps::load(
Instruction::I32Load8U(memarg),
module,
Expand All @@ -1967,9 +1972,10 @@ fn i32_load_16_s(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1])?;
builder.allocs.operands.push(Some(ValType::I32));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 4);
no_traps::load(
Instruction::I32Load16S(memarg),
module,
Expand All @@ -1988,9 +1994,10 @@ fn i32_load_16_u(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1])?;
builder.allocs.operands.push(Some(ValType::I32));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 4);
no_traps::load(
Instruction::I32Load16U(memarg),
module,
Expand All @@ -2009,9 +2016,10 @@ fn i64_load_8_s(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0])?;
let mut memarg = mem_arg(u, module, builder, &[0])?;
builder.allocs.operands.push(Some(ValType::I64));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 8);
no_traps::load(
Instruction::I64Load8S(memarg),
module,
Expand All @@ -2030,9 +2038,10 @@ fn i64_load_16_s(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1])?;
builder.allocs.operands.push(Some(ValType::I64));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 8);
no_traps::load(
Instruction::I64Load16S(memarg),
module,
Expand All @@ -2051,9 +2060,10 @@ fn i64_load_32_s(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1, 2])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1, 2])?;
builder.allocs.operands.push(Some(ValType::I64));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 8);
no_traps::load(
Instruction::I64Load32S(memarg),
module,
Expand All @@ -2072,9 +2082,10 @@ fn i64_load_8_u(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0])?;
let mut memarg = mem_arg(u, module, builder, &[0])?;
builder.allocs.operands.push(Some(ValType::I64));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 8);
no_traps::load(
Instruction::I64Load8U(memarg),
module,
Expand All @@ -2093,9 +2104,10 @@ fn i64_load_16_u(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1])?;
builder.allocs.operands.push(Some(ValType::I64));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 8);
no_traps::load(
Instruction::I64Load16U(memarg),
module,
Expand All @@ -2114,9 +2126,10 @@ fn i64_load_32_u(
builder: &mut CodeBuilder,
instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, &[0, 1, 2])?;
let mut memarg = mem_arg(u, module, builder, &[0, 1, 2])?;
builder.allocs.operands.push(Some(ValType::I64));
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 8);
no_traps::load(
Instruction::I64Load32U(memarg),
module,
Expand Down Expand Up @@ -4786,9 +4799,10 @@ macro_rules! simd_load {

instructions: &mut Vec<Instruction>,
) -> Result<()> {
let memarg = mem_arg(u, module, builder, $alignments)?;
let mut memarg = mem_arg(u, module, builder, $alignments)?;
builder.push_operands(&[ValType::V128]);
if module.config.disallow_traps() {
memarg.offset = memarg.offset.min(u64::MAX - 16);
no_traps::load(
Instruction::$instruction(memarg),
module,
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/no-traps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fuzz_target!(|data: &[u8]| {
match func.call(&mut store, &args, &mut results) {
Ok(_) => continue,
Err(err) if err.to_string().contains("all fuel consumed") => continue,
Err(_) => panic!("generated wasm trapped in non-trapping mode"),
Err(err) => panic!("generated wasm trapped in non-trapping mode: {}", err),
}
}
_ => continue,
Expand Down

0 comments on commit d091301

Please sign in to comment.