Closed clearloop closed 3 years ago
Here is an example of handling or not
#[no_mangle]
pub fn _start() {
panic!("Hello, world!");
}
Error: failed to run main module `target/wasm32-unknown-unknown/debug/bt.wasm`
Caused by:
0: failed to invoke command default
1: wasm trap: unreachable
wasm backtrace:
0: 0x1cda - <unknown>!__rust_start_panic
1: 0x1cce - <unknown>!rust_panic
2: 0x1c9e - <unknown>!std::panicking::rust_panic_with_hook::hc5713da015ebaa19
3: 0x26e - <unknown>!std::panicking::begin_panic::{{closure}}::h8e62ab0ea555186f
4: 0xfba - <unknown>!std::sys_common::backtrace::__rust_end_short_backtrace::h34a944558df1326a
5: 0x15c - <unknown>!std::panicking::begin_panic::h03c636dac2b8fb70
6: 0x1a65 - <unknown>!_start
error: failed to run `target/wasm32-unknown-unknown/debug/bt.wasm`
ā”‚ 1: RuntimeError: unreachable
at __rust_start_panic (bt.wasm[67]:0x1cda)
at rust_panic (bt.wasm[66]:0x1cce)
at std::panicking::rust_panic_with_hook::hc5713da015ebaa19 (bt.wasm[65]:0x1c9e)
at std::panicking::begin_panic::{{closure}}::h8e62ab0ea555186f (bt.wasm[2]:0x26e)
at std::sys_common::backtrace::__rust_end_short_backtrace::h34a944558df1326a (bt.wasm[36]:0xfba)
at std::panicking::begin_panic::h03c636dac2b8fb70 (bt.wasm[0]:0x15c)
at _start (bt.wasm[55]:0x1a65)
ā•°ā”€> 2: unreachable
Runtime exception: wavm.reachedUnreachable
Call stack:
host!/Users/mercury/.wasmer/bin/wavm!unreachableTrap(WAVM::Runtime::ContextRuntimeData*)+41
wasm!target/wasm32-unknown-unknown/debug/bt.wasm!__rust_start_panic+0
wasm!target/wasm32-unknown-unknown/debug/bt.wasm!rust_panic+14
wasm!target/wasm32-unknown-unknown/debug/bt.wasm!_ZN3std9panicking20rust_panic_with_hook17hc5713da015ebaa19E+109
wasm!target/wasm32-unknown-unknown/debug/bt.wasm!_ZN3std9panicking11begin_panic28_$u7b$$u7b$closure$u7d$$u7d$17h8e62ab0ea555186fE+65
wasm!target/wasm32-unknown-unknown/debug/bt.wasm!_ZN3std10sys_common9backtrace26__rust_end_short_backtrace17h34a944558df1326aE+41
wasm!target/wasm32-unknown-unknown/debug/bt.wasm!_ZN3std9panicking11begin_panic17h03c636dac2b8fb70E+34
wasm!target/wasm32-unknown-unknown/debug/bt.wasm!_start+13
thnk!C to WASM thunk!()->()+0
host!/Users/mercury/.wasmer/bin/wavm!WAVM::Platform::catchSignals(void (*)(void*), bool (*)(void*, WAVM::Platform::Signal, WAVM::Platform::CallStack&&), void*)+151
host!/Users/mercury/.wasmer/bin/wavm!WAVM::Runtime::unwindSignalsAsExceptions(std::__1::function<void ()> const&)+87
host!/Users/mercury/.wasmer/bin/wavm!WAVM::Runtime::invokeFunction(WAVM::Runtime::Context*, WAVM::Runtime::Function const*, WAVM::IR::FunctionType, WAVM::IR::UntaggedValue const*, WAVM::IR::UntaggedValue*)+317
host!/Users/mercury/.wasmer/bin/wavm!State::execute(WAVM::IR::Module const&, WAVM::Runtime::Instance*)+1393
host!/Users/mercury/.wasmer/bin/wavm!State::run(char**)+8474
host!/Users/mercury/.wasmer/bin/wavm!std::__1::__function::__func<State::runAndCatchRuntimeExceptions(char**)::'lambda'(), std::__1::allocator<State::runAndCatchRuntimeExceptions(char**)::'lambda'()>, void ()>::operator()()+21
<2 redundant frames omitted>
host!/Users/mercury/.wasmer/bin/wavm!WAVM::Runtime::catchRuntimeExceptions(std::__1::function<void ()> const&, std::__1::function<void (WAVM::Runtime::Exception*)> const&)+18
host!/Users/mercury/.wasmer/bin/wavm!State::runAndCatchRuntimeExceptions(char**)+104
host!/Users/mercury/.wasmer/bin/wavm!main+1290
zsh: abort wavm run --abi=emscripten --function=_start
Error: [Fatal] repl_call: [trap] unreachable executed
Error: [trap] unreachable executed ()
thread 'main' panicked at ': Trap(Trap { kind: Unreachable })', src/bin/instantiate.rs:87:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
The panic trace is stored in the name section, which is listed in the appendix of WebAssembly Specification.
parity-wasm
provides a parse_names
function for parsing name_section
in struct Module
Corresponding custom section with proper header will convert to name sections If some of them will fail to be decoded, Err variant is returned with the list of (index, Error) tuples of failed sections.
This function can generate the target name section but need to be filtered.
wasmer
builds RuntimeErrorInner
with TrapCode
and program counter
,
struct RuntimeErrorInner {
/// The source error (this can be a custom user `Error` or a [`TrapCode`])
source: RuntimeErrorSource,
/// The reconstructed Wasm trace (from the native trace and the `GlobalFrameInfo`).
wasm_trace: Vec<FrameInfo>,
/// The native backtrace
native_trace: Backtrace,
}
impl RuntimeErrorInner {
fn from_trap(trap: Tap) -> Self {
// ...
}
}
enum Trap {
// ...
/// A trap raised from machine code generated from Wasm
Wasm {
/// The program counter in generated code where this trap happened.
pc: usize,
/// Native stack backtrace at the time the trap occurred
backtrace: Backtrace,
/// Optional trapcode associated to the signal that caused the trap
signal_trap: Option<TrapCode>,
},
}
For wasmtime
, there is a FrameInfo
generated along with FunctionInfo
from program counter
/// Information about trap.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct TrapInformation {
/// The offset of the trapping instruction in native code.
/// It is relative to the beginning of the function.
pub code_offset: binemit::CodeOffset,
/// Code of the trap.
pub trap_code: ir::TrapCode,
}
struct TrapInner {
reason: TrapReason,
wasm_trace: Vec<FrameInfo>,
native_trace: Backtrace,
}
/// Creates a new `Trap`.
///
/// * `store` - this is optionally provided, if available. If `None` we'll
/// look up the last store, if available, used to call wasm code on the
/// stack.
///
/// * `trap_pc` - this is the precise program counter, if available, that
/// wasm trapped at. This is used when learning about the wasm stack trace
/// to ensure we assign the correct source to every frame.
///
/// * `reason` - this is the wasmtime-internal reason for why this trap is
/// being created.
///
/// * `native_trace` - this is a captured backtrace from when the trap
/// occurred, and this will iterate over the frames to find frames that
/// lie in wasm jit code.
fn new_with_trace(
store: Option<&Store>,
trap_pc: Option<usize>,
reason: TrapReason,
native_trace: Backtrace,
) -> Self {}
So what is the program counter? How to get it?
/// The inner `u32` points to what?
struct Func(u32);
let fn_name = module.function_names.get(&fn_index);
Prints functions in Call Stack (wasmi)
[
FuncRef(
Internal { signature=Signature { params: [], return_type: None } },
),
FuncRef(
Internal { signature=Signature { params: [I32, I32, I32], return_type: None } },
),
FuncRef(
Internal { signature=Signature { params: [I32], return_type: None } },
),
FuncRef(
Internal { signature=Signature { params: [I32], return_type: None } },
),
FuncRef(
Internal { signature=Signature { params: [I32, I32, I32, I32], return_type: None } },
),
FuncRef(
Internal { signature=Signature { params: [I32, I32], return_type: None } },
),
]
Comparing to the ideal outputs
Error: failed to run main module `panic.wasm`
Caused by:
0: failed to invoke command default
1: wasm trap: unreachable
wasm backtrace:
0: 0x3a93 - <unknown>!__rust_start_panic
1: 0x3a87 - <unknown>!rust_panic
2: 0x3a57 - <unknown>!std::panicking::rust_panic_with_hook::h7ba07724d623fbd6
3: 0x17eb - <unknown>!std::panicking::begin_panic::{{closure}}::haa116d4044ff002f
4: 0x1cf6 - <unknown>!std::sys_common::backtrace::__rust_end_short_backtrace::h4273a622fa86868a
5: 0x16d9 - <unknown>!std::panicking::begin_panic::hc8f5829adc10d800
6: 0x1678 - <unknown>!_start
It's fine.
[
"rust_panic",
"_ZN3std9panicking20rust_panic_with_hook17hc5713da015ebaa19E",
"_ZN3std9panicking11begin_panic28_$u7b$$u7b$closure$u7d$$u7d$17he51f9abd5f6c28d2E",
"_ZN3std10sys_common9backtrace26__rust_end_short_backtrace17hc867af7cfda96dafE",
"_ZN3std9panicking11begin_panic17h0a859a469eb06beaE",
"_ZN5panic23panic_in_wasm_backtrace17ha67ca05cd299040fE",
"_start",
]
Try to decode with https://github.com/alexcrichton/rustc-demangle
[
rust_panic,
std::panicking::rust_panic_with_hook,
std::panicking::begin_panic::{{closure}},
std::sys_common::backtrace::__rust_end_short_backtrace,
std::panicking::begin_panic,
panic::panic_in_wasm_backtrace,
_start,
]
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Trap(Trap { kind: Unreachable })', src/bin/instantiate.rs:84:6
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Done, patractlabs/wasmi@80bb84b.
Traps
Under some conditions, certain instructions may produce a trap, which immediately aborts execution. Traps cannot be handled by WebAssembly code, but are reported to the outside environment, where they typically can be caught.
#Traps concept in WebAssembly Overview
Administrative Instructions in WebAssembly Execution
In order to express the reduction of traps, calls, and control instructions, the syntax of instructions is extended to include the following administrative instructions:
The trap instruction represents the occurrence of a trap. Traps are bubbled up through nested instruction sequences, ultimately reducing the entire program to a single š¯—¨š¯—‹š¯–ŗš¯—‰ instruction, signaling abrupt termination.
#Administrative Instructions
Runtime Result
A result is the outcome of a computation. It is either a sequence of values or a trap.
#Trap as results in runtime