Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/c-api/include/wasmtime/extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ typedef struct wasmtime_global {
size_t index;
} wasmtime_global_t;

/// \brief Disciminant of #wasmtime_extern_t
/// \brief Discriminant of #wasmtime_extern_t
typedef uint8_t wasmtime_extern_kind_t;

/// \brief Value of #wasmtime_extern_kind_t meaning that #wasmtime_extern_t is a
Expand Down
46 changes: 46 additions & 0 deletions crates/c-api/include/wasmtime/trap.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,41 @@
extern "C" {
#endif

/**
* \brief Code of an instruction trap.
*
* See #wasmtime_trap_code_enum for possible values.
*/
typedef uint8_t wasmtime_trap_code_t;

/**
* \brief Trap codes for instruction traps.
*/
enum wasmtime_trap_code_enum {
/// The current stack space was exhausted.
WASMTIME_TRAP_CODE_STACK_OVERFLOW,
/// An out-of-bounds memory access.
WASMTIME_TRAP_CODE_MEMORY_OUT_OF_BOUNDS,
/// A wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
WASMTIME_TRAP_CODE_HEAP_MISALIGNED,
/// An out-of-bounds access to a table.
WASMTIME_TRAP_CODE_TABLE_OUT_OF_BOUNDS,
/// Indirect call to a null table entry.
WASMTIME_TRAP_CODE_INDIRECT_CALL_TO_NULL,
/// Signature mismatch on indirect call.
WASMTIME_TRAP_CODE_BAD_SIGNATURE,
/// An integer arithmetic operation caused an overflow.
WASMTIME_TRAP_CODE_INTEGER_OVERFLOW,
/// An integer division by zero.
WASMTIME_TRAP_CODE_INTEGER_DIVISION_BY_ZERO,
/// Failed float-to-int conversion.
WASMTIME_TRAP_CODE_BAD_CONVERSION_TO_INTEGER,
/// Code that was supposed to have been unreachable was reached.
WASMTIME_TRAP_CODE_UNREACHABLE_CODE_REACHED,
/// Execution has potentially run too long and may be interrupted.
WASMTIME_TRAP_CODE_INTERRUPT,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here it's ok to skip the enum { .. } wrapper, and I think the value of each #define constant will need to be listed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I had a bunch of #defines first, then decided to model this after the config enums like

enum wasmtime_opt_level_enum { // OptLevel
/// Generated code will not be optimized at all.
WASMTIME_OPT_LEVEL_NONE,
/// Generated code will be optimized purely for speed.
WASMTIME_OPT_LEVEL_SPEED,
/// Generated code will be optimized, but some speed optimizations are
/// disabled if they cause the generated code to be significantly larger.
WASMTIME_OPT_LEVEL_SPEED_AND_SIZE,
};

...and didn't follow through properly 😬 I've updated the code using a proper enum instead of defines. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh I could go either way, I don't actually know enough about C to know whether these are really that different, and they feel like the same to me. I'm happy to defer to whichever you feel is more appropriate here!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a C expert either -- it felt to be a tad more consistent going with the enum definition. Updated ✔️


/**
* \brief Creates a new trap.
*
Expand All @@ -23,6 +58,17 @@ extern "C" {
*/
WASM_API_EXTERN wasm_trap_t *wasmtime_trap_new(const char *msg, size_t msg_len);

/**
* \brief Attempts to extract the trap code from this trap.
*
* Returns `true` if the trap is an instruction trap triggered while
* executing Wasm. If `true` is returned then the trap code is returned
* through the `code` pointer. If `false` is returned then this is not
* an instruction trap -- traps can also be created using wasm_trap_new,
* or occur with WASI modules exiting with a certain exit code.
*/
WASM_API_EXTERN bool wasmtime_trap_code(const wasm_trap_t*, wasmtime_trap_code_t *code);

/**
* \brief Attempts to extract a WASI-specific exit status from this trap.
*
Expand Down
26 changes: 25 additions & 1 deletion crates/c-api/src/trap.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
use once_cell::unsync::OnceCell;
use wasmtime::Trap;
use wasmtime::{Trap, TrapCode};

#[repr(C)]
#[derive(Clone)]
Expand Down Expand Up @@ -91,6 +91,30 @@ pub extern "C" fn wasm_trap_trace(raw: &wasm_trap_t, out: &mut wasm_frame_vec_t)
out.set_buffer(vec);
}

#[no_mangle]
pub extern "C" fn wasmtime_trap_code(raw: &wasm_trap_t, code: &mut i32) -> bool {
match raw.trap.trap_code() {
Some(c) => {
*code = match c {
TrapCode::StackOverflow => 0,
TrapCode::MemoryOutOfBounds => 1,
TrapCode::HeapMisaligned => 2,
TrapCode::TableOutOfBounds => 3,
TrapCode::IndirectCallToNull => 4,
TrapCode::BadSignature => 5,
TrapCode::IntegerOverflow => 6,
TrapCode::IntegerDivisionByZero => 7,
TrapCode::BadConversionToInteger => 8,
TrapCode::UnreachableCodeReached => 9,
TrapCode::Interrupt => 10,
_ => unreachable!(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you leave a comment near enum TrapCode and its #[non_exhaustive] that any additions should get added here too?

};
true
}
None => false,
}
}

#[no_mangle]
pub extern "C" fn wasmtime_trap_exit_status(raw: &wasm_trap_t, status: &mut i32) -> bool {
match raw.trap.i32_exit_status() {
Expand Down
8 changes: 8 additions & 0 deletions crates/wasmtime/src/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ impl fmt::Display for TrapReason {
/// A trap code describing the reason for a trap.
///
/// All trap instructions have an explicit trap code.
///
/// The code can be accessed from the c-api, where the possible values are translated
/// into enum values defined there:
///
/// * `wasm_trap_code` in c-api/src/trap.rs, and
/// * `wasmtime_trap_code_enum` in c-api/include/wasmtime/trap.h.
///
/// These need to be kept in sync.
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum TrapCode {
Expand Down
4 changes: 4 additions & 0 deletions examples/interrupt.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ int main() {
printf("Got a trap!...\n");

// `trap` can be inspected here to see the trap message has an interrupt in it
wasmtime_trap_code_t code;
ok = wasmtime_trap_code(trap, &code);
assert(ok);
assert(code == WASMTIME_TRAP_CODE_INTERRUPT);
wasm_trap_delete(trap);

wasmtime_store_delete(store);
Expand Down