You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
7.9 KiB
260 lines
7.9 KiB
use anyhow::bail;
|
|
use wasmtime::*;
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn coredump_attached_to_error() -> Result<()> {
|
|
let mut config = Config::default();
|
|
config.coredump_on_trap(true);
|
|
let engine = Engine::new(&config).unwrap();
|
|
let mut store = Store::<()>::new(&engine, ());
|
|
|
|
let wat = r#"
|
|
(module
|
|
(func $hello (import "" "hello"))
|
|
(func (export "run") (call $hello))
|
|
)
|
|
"#;
|
|
|
|
let module = Module::new(store.engine(), wat)?;
|
|
let hello_type = FuncType::new(store.engine(), None, None);
|
|
let hello_func = Func::new(&mut store, hello_type, |_, _, _| bail!("test 123"));
|
|
|
|
let instance = Instance::new(&mut store, &module, &[hello_func.into()])?;
|
|
let run_func = instance.get_typed_func::<(), ()>(&mut store, "run")?;
|
|
|
|
let e = run_func.call(&mut store, ()).unwrap_err();
|
|
assert!(format!("{e:?}").contains("test 123"));
|
|
|
|
assert!(
|
|
e.downcast_ref::<WasmCoreDump>().is_some(),
|
|
"error should contain a WasmCoreDump"
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn coredump_has_stack() -> Result<()> {
|
|
let mut config = Config::default();
|
|
config.coredump_on_trap(true);
|
|
let engine = Engine::new(&config).unwrap();
|
|
let mut store = Store::<()>::new(&engine, ());
|
|
|
|
let wat = r#"
|
|
(module
|
|
(func $a (export "a")
|
|
call $b
|
|
)
|
|
(func $b
|
|
call $c
|
|
)
|
|
(func $c
|
|
unreachable
|
|
)
|
|
)
|
|
"#;
|
|
|
|
let module = Module::new(store.engine(), wat)?;
|
|
let instance = Instance::new(&mut store, &module, &[])?;
|
|
let a_func = instance.get_typed_func::<(), ()>(&mut store, "a")?;
|
|
|
|
let e = a_func.call(&mut store, ()).unwrap_err();
|
|
let cd = e.downcast_ref::<WasmCoreDump>().unwrap();
|
|
assert_eq!(cd.frames().len(), 3);
|
|
assert_eq!(cd.frames()[0].func_name().unwrap(), "c");
|
|
assert_eq!(cd.frames()[1].func_name().unwrap(), "b");
|
|
assert_eq!(cd.frames()[2].func_name().unwrap(), "a");
|
|
let _ = cd.serialize(&mut store, "stack");
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn coredump_has_modules_and_instances() -> Result<()> {
|
|
let mut config = Config::default();
|
|
config.coredump_on_trap(true);
|
|
let engine = Engine::new(&config).unwrap();
|
|
let mut linker = Linker::new(&engine);
|
|
let mut store = Store::<()>::new(&engine, ());
|
|
|
|
let wat1 = r#"
|
|
(module $foo
|
|
(import "bar" "b" (func $b))
|
|
(func (export "a")
|
|
call $b
|
|
)
|
|
)
|
|
"#;
|
|
let wat2 = r#"
|
|
(module $bar
|
|
(func (export "b")
|
|
unreachable
|
|
)
|
|
)
|
|
"#;
|
|
let module1 = Module::new(store.engine(), wat1)?;
|
|
let module2 = Module::new(store.engine(), wat2)?;
|
|
let linking2 = linker.instantiate(&mut store, &module2)?;
|
|
linker.instance(&mut store, "bar", linking2)?;
|
|
|
|
let linking1 = linker.instantiate(&mut store, &module1)?;
|
|
let a_func = linking1.get_typed_func::<(), ()>(&mut store, "a")?;
|
|
|
|
let e = a_func.call(&mut store, ()).unwrap_err();
|
|
let cd = e.downcast_ref::<WasmCoreDump>().unwrap();
|
|
assert_eq!(cd.modules().len(), 2);
|
|
assert_eq!(cd.instances().len(), 2);
|
|
let _ = cd.serialize(&mut store, "modules-and-instances");
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn coredump_has_host_globals_and_memory() -> Result<()> {
|
|
let mut config = Config::default();
|
|
config.coredump_on_trap(true);
|
|
let engine = Engine::new(&config).unwrap();
|
|
|
|
let module = Module::new(
|
|
&engine,
|
|
r#"
|
|
(module
|
|
(import "memory" "memory" (memory 1))
|
|
(global $myglobal (import "global" "global") (mut i32))
|
|
(func (export "a") (result i32)
|
|
unreachable
|
|
)
|
|
(export "memory" (memory 0))
|
|
(export "global" (global 0))
|
|
)
|
|
"#,
|
|
)?;
|
|
|
|
let mut store = Store::<()>::new(&engine, ());
|
|
let mut linker = Linker::new(&engine);
|
|
|
|
let memory = Memory::new(&mut store, MemoryType::new(1, None))?;
|
|
linker.define(&mut store, "memory", "memory", memory)?;
|
|
|
|
let global = Global::new(
|
|
&mut store,
|
|
GlobalType::new(ValType::I32, Mutability::Var),
|
|
Val::I32(0),
|
|
)?;
|
|
linker.define(&mut store, "global", "global", global)?;
|
|
|
|
let instance = linker.instantiate(&mut store, &module)?;
|
|
|
|
// Each time we extract the exports, it puts them in the `StoreData`. Our
|
|
// core dumps need to be robust to duplicate entries in the `StoreData`.
|
|
for _ in 0..10 {
|
|
let _ = instance.get_global(&mut store, "global").unwrap();
|
|
let _ = instance.get_memory(&mut store, "memory").unwrap();
|
|
}
|
|
|
|
let a_func = instance.get_typed_func::<(), i32>(&mut store, "a")?;
|
|
let err = a_func.call(&mut store, ()).unwrap_err();
|
|
let core_dump = err.downcast_ref::<WasmCoreDump>().unwrap();
|
|
assert_eq!(core_dump.globals().len(), 1);
|
|
assert_eq!(core_dump.memories().len(), 1);
|
|
assert_eq!(core_dump.instances().len(), 1);
|
|
let _ = core_dump.serialize(&mut store, "host-globals-and-memory");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn coredump_has_defined_globals_and_memory() -> Result<()> {
|
|
let mut config = Config::default();
|
|
config.coredump_on_trap(true);
|
|
let engine = Engine::new(&config).unwrap();
|
|
|
|
let module = Module::new(
|
|
&engine,
|
|
r#"
|
|
(module
|
|
(global (mut i32) (i32.const 42))
|
|
(memory 1)
|
|
(func (export "a")
|
|
unreachable
|
|
)
|
|
)
|
|
"#,
|
|
)?;
|
|
|
|
let mut store = Store::<()>::new(&engine, ());
|
|
let instance = Instance::new(&mut store, &module, &[])?;
|
|
|
|
let a_func = instance.get_typed_func::<(), ()>(&mut store, "a")?;
|
|
let err = a_func.call(&mut store, ()).unwrap_err();
|
|
let core_dump = err.downcast_ref::<WasmCoreDump>().unwrap();
|
|
assert_eq!(core_dump.globals().len(), 1);
|
|
assert_eq!(core_dump.memories().len(), 1);
|
|
assert_eq!(core_dump.instances().len(), 1);
|
|
let _ = core_dump.serialize(&mut store, "defined-globals-and-memory");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(miri, ignore)]
|
|
fn multiple_globals_memories_and_instances() -> Result<()> {
|
|
let mut config = Config::default();
|
|
config.wasm_multi_memory(true);
|
|
config.coredump_on_trap(true);
|
|
let engine = Engine::new(&config).unwrap();
|
|
let mut store = Store::<()>::new(&engine, ());
|
|
let mut linker = Linker::new(&engine);
|
|
|
|
let memory = Memory::new(&mut store, MemoryType::new(1, None))?;
|
|
linker.define(&mut store, "host", "memory", memory)?;
|
|
|
|
let global = Global::new(
|
|
&mut store,
|
|
GlobalType::new(ValType::I32, Mutability::Var),
|
|
Val::I32(0),
|
|
)?;
|
|
linker.define(&mut store, "host", "global", global)?;
|
|
|
|
let module_a = Module::new(
|
|
&engine,
|
|
r#"
|
|
(module
|
|
(memory (export "memory") 1)
|
|
(global (export "global") (mut i32) (i32.const 0))
|
|
)
|
|
"#,
|
|
)?;
|
|
let instance_a = linker.instantiate(&mut store, &module_a)?;
|
|
linker.instance(&mut store, "a", instance_a)?;
|
|
|
|
let module_b = Module::new(
|
|
&engine,
|
|
r#"
|
|
(module
|
|
(import "host" "memory" (memory 1))
|
|
(import "host" "global" (global (mut i32)))
|
|
(import "a" "memory" (memory 1))
|
|
(import "a" "global" (global (mut i32)))
|
|
|
|
(func (export "trap")
|
|
unreachable
|
|
)
|
|
)
|
|
"#,
|
|
)?;
|
|
let instance_b = linker.instantiate(&mut store, &module_b)?;
|
|
|
|
let trap_func = instance_b.get_typed_func::<(), ()>(&mut store, "trap")?;
|
|
let err = trap_func.call(&mut store, ()).unwrap_err();
|
|
let core_dump = err.downcast_ref::<WasmCoreDump>().unwrap();
|
|
assert_eq!(core_dump.globals().len(), 2);
|
|
assert_eq!(core_dump.memories().len(), 2);
|
|
assert_eq!(core_dump.instances().len(), 2);
|
|
let _ = core_dump.serialize(&mut store, "multi");
|
|
|
|
Ok(())
|
|
}
|
|
|