use rwasm::{
always_failing_syscall_handler, instruction_set, ExecutionEngine, ImportLinker, InstructionSet,
RwasmModuleBuilder, RwasmStore, TrapCode, Value,
};
const UNGROWN_TABLE: u16 = 3;
fn module(code_section: InstructionSet, elem_section: &[u32]) -> rwasm::RwasmModule {
RwasmModuleBuilder::new(code_section)
.with_elem_section(elem_section)
.build()
}
fn execute(code_section: InstructionSet, result: &mut [Value]) -> Result<(), TrapCode> {
let module = module(code_section, &[]);
let engine = ExecutionEngine::new();
let mut store = RwasmStore::new(
ImportLinker::default().into(),
(),
always_failing_syscall_handler,
None,
None,
);
engine.execute(&mut store, &module, &[], result)
}
fn execute_and_trap(code_section: InstructionSet) -> TrapCode {
execute(code_section, &mut []).expect_err("execution must trap")
}
#[test]
fn test_table_size_of_ungrown_table_is_zero() {
let mut result = [Value::I32(-1)];
execute(
instruction_set! {
TableSize(UNGROWN_TABLE)
Return
},
&mut result,
)
.unwrap();
assert_eq!(result[0].i32(), Some(0));
}
#[test]
fn test_table_get_of_ungrown_table_traps() {
let trap_code = execute_and_trap(instruction_set! {
I32Const(0)
TableGet(UNGROWN_TABLE)
Drop
Return
});
assert_eq!(trap_code, TrapCode::TableOutOfBounds);
}
#[test]
fn test_table_set_of_ungrown_table_traps() {
let trap_code = execute_and_trap(instruction_set! {
I32Const(0) I32Const(1) TableSet(UNGROWN_TABLE)
Return
});
assert_eq!(trap_code, TrapCode::TableOutOfBounds);
}
#[test]
fn test_table_fill_of_ungrown_table_traps() {
let trap_code = execute_and_trap(instruction_set! {
I32Const(0) I32Const(0) I32Const(1) TableFill(UNGROWN_TABLE)
Return
});
assert_eq!(trap_code, TrapCode::TableOutOfBounds);
}
#[test]
fn test_empty_table_fill_of_ungrown_table_succeeds() {
execute(
instruction_set! {
I32Const(0) I32Const(0) I32Const(0) TableFill(UNGROWN_TABLE)
Return
},
&mut [],
)
.unwrap();
}
#[test]
fn test_table_copy_of_ungrown_tables_traps() {
let trap_code = execute_and_trap(instruction_set! {
I32Const(0) I32Const(0) I32Const(1) .op_table_copy(UNGROWN_TABLE, UNGROWN_TABLE + 1)
Return
});
assert_eq!(trap_code, TrapCode::TableOutOfBounds);
}
#[test]
fn test_empty_table_copy_of_ungrown_tables_succeeds() {
execute(
instruction_set! {
I32Const(0) I32Const(0) I32Const(0) .op_table_copy(UNGROWN_TABLE, UNGROWN_TABLE + 1)
Return
},
&mut [],
)
.unwrap();
}
#[test]
fn test_table_copy_within_ungrown_table_traps() {
let trap_code = execute_and_trap(instruction_set! {
I32Const(0) I32Const(0) I32Const(1) .op_table_copy(UNGROWN_TABLE, UNGROWN_TABLE)
Return
});
assert_eq!(trap_code, TrapCode::TableOutOfBounds);
}
#[test]
fn test_table_init_into_ungrown_table_traps() {
let module = module(
instruction_set! {
I32Const(0) I32Const(0) I32Const(1) TableInit(1)
TableGet(UNGROWN_TABLE) Return
},
&[0],
);
let engine = ExecutionEngine::new();
let mut store = RwasmStore::new(
ImportLinker::default().into(),
(),
always_failing_syscall_handler,
None,
None,
);
let trap_code = engine
.execute(&mut store, &module, &[], &mut [])
.expect_err("execution must trap");
assert_eq!(trap_code, TrapCode::TableOutOfBounds);
}
#[test]
fn test_call_indirect_through_ungrown_table_traps() {
let trap_code = execute_and_trap(instruction_set! {
I32Const(0) CallIndirect(0)
TableGet(UNGROWN_TABLE) Return
});
assert_eq!(trap_code, TrapCode::TableOutOfBounds);
}
#[test]
fn test_return_call_indirect_through_ungrown_table_traps() {
let trap_code = execute_and_trap(instruction_set! {
I32Const(0) ReturnCallIndirect(0)
TableGet(UNGROWN_TABLE) Return
});
assert_eq!(trap_code, TrapCode::TableOutOfBounds);
}
#[test]
fn test_grown_table_still_reports_its_size() {
let mut result = [Value::I32(-1)];
execute(
instruction_set! {
I32Const(0) I32Const(2) TableGrow(UNGROWN_TABLE)
Drop
TableSize(UNGROWN_TABLE)
Return
},
&mut result,
)
.unwrap();
assert_eq!(result[0].i32(), Some(2));
}