Skip to content

Commit 23e27ba

Browse files
authored
c-api: new wasmtime_trap_new_code function (#10765)
* c-api: new wasmtime_trap_new_code function * review comments * remove accidental include
1 parent 8d853cc commit 23e27ba

File tree

5 files changed

+100
-19
lines changed

5 files changed

+100
-19
lines changed

crates/c-api/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,13 @@ fn main() {
7272
.compile("your_library");
7373
}
7474
```
75+
76+
## Testing
77+
78+
Running tests for the C API can be done using cmake from the root of the repo:
79+
80+
```sh
81+
$ cmake -S examples -B examples/build -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTS=ON
82+
$ cmake --build examples/build --config Debug
83+
$ CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target test
84+
```

crates/c-api/include/wasmtime/trap.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,40 @@ enum wasmtime_trap_code_enum {
4747
WASMTIME_TRAP_CODE_UNREACHABLE_CODE_REACHED,
4848
/// Execution has potentially run too long and may be interrupted.
4949
WASMTIME_TRAP_CODE_INTERRUPT,
50+
/// When the `component-model` feature is enabled this trap represents a
51+
/// function that was `canon lift`'d, then `canon lower`'d, then called.
52+
/// This combination of creation of a function in the component model
53+
/// generates a function that always traps and, when called, produces this
54+
/// flavor of trap.
55+
WASMTIME_TRAP_CODE_ALWAYS_TRAP_ADAPTER,
5056
/// Execution has run out of the configured fuel amount.
5157
WASMTIME_TRAP_CODE_OUT_OF_FUEL,
58+
/// Used to indicate that a trap was raised by atomic wait operations on non
59+
/// shared memory.
60+
WASMTIME_TRAP_CODE_ATOMIC_WAIT_NON_SHARED_MEMORY,
61+
/// Call to a null reference.
62+
WASMTIME_TRAP_CODE_NULL_REFERENCE,
63+
/// Attempt to access beyond the bounds of an array.
64+
WASMTIME_TRAP_CODE_ARRAY_OUT_OF_BOUNDS,
65+
/// Attempted an allocation that was too large to succeed.
66+
WASMTIME_TRAP_CODE_ALLOCATION_TOO_LARGE,
67+
/// Attempted to cast a reference to a type that it is not an instance of.
68+
WASMTIME_TRAP_CODE_CAST_FAILURE,
69+
/// When the `component-model` feature is enabled this trap represents a
70+
/// scenario where one component tried to call another component but it
71+
/// would have violated the reentrance rules of the component model,
72+
/// triggering a trap instead.
73+
WASMTIME_TRAP_CODE_CANNOT_ENTER_COMPONENT,
74+
/// Async-lifted export failed to produce a result by calling `task.return`
75+
/// before returning `STATUS_DONE` and/or after all host tasks completed.
76+
WASMTIME_TRAP_CODE_NO_ASYNC_RESULT,
77+
/// A Pulley opcode was executed at runtime when the opcode was disabled at
78+
/// compile time.
79+
WASMTIME_TRAP_CODE_DISABLED_OPCODE,
5280
};
5381

5482
/**
55-
* \brief Creates a new trap.
83+
* \brief Creates a new trap with the given message.
5684
*
5785
* \param msg the message to associate with this trap
5886
* \param msg_len the byte length of `msg`
@@ -61,6 +89,15 @@ enum wasmtime_trap_code_enum {
6189
*/
6290
WASM_API_EXTERN wasm_trap_t *wasmtime_trap_new(const char *msg, size_t msg_len);
6391

92+
/**
93+
* \brief Creates a new trap from the given trap code.
94+
*
95+
* \param code the trap code to associate with this trap
96+
*
97+
* The #wasm_trap_t returned is owned by the caller.
98+
*/
99+
WASM_API_EXTERN wasm_trap_t *wasmtime_trap_new_code(wasmtime_trap_code_t code);
100+
64101
/**
65102
* \brief Attempts to extract the trap code from this trap.
66103
*

crates/c-api/include/wasmtime/trap.hh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ public:
129129
explicit Trap(std::string_view msg)
130130
: Trap(wasmtime_trap_new(msg.data(), msg.size())) {}
131131

132-
/// Returns the descriptive message associated with this trap
132+
/// Creates a new trap with the given wasmtime trap code.
133+
Trap(wasmtime_trap_code_enum code) : Trap(wasmtime_trap_new_code(code)) {}
134+
135+
/// Returns the descriptive message associated with this trap.
133136
std::string message() const {
134137
wasm_byte_vec_t msg;
135138
wasm_trap_message(ptr.get(), &msg);

crates/c-api/src/trap.rs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ pub unsafe extern "C" fn wasmtime_trap_new(message: *const u8, len: usize) -> Bo
6565
})
6666
}
6767

68+
#[unsafe(no_mangle)]
69+
pub unsafe extern "C" fn wasmtime_trap_new_code(code: u8) -> Box<wasm_trap_t> {
70+
let trap = Trap::from_u8(code).unwrap();
71+
Box::new(wasm_trap_t {
72+
error: Error::new(trap),
73+
})
74+
}
75+
6876
#[unsafe(no_mangle)]
6977
pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) {
7078
let mut buffer = Vec::new();
@@ -121,22 +129,7 @@ pub extern "C" fn wasmtime_trap_code(raw: &wasm_trap_t, code: &mut u8) -> bool {
121129
Some(trap) => trap,
122130
None => return false,
123131
};
124-
*code = match trap {
125-
Trap::StackOverflow => 0,
126-
Trap::MemoryOutOfBounds => 1,
127-
Trap::HeapMisaligned => 2,
128-
Trap::TableOutOfBounds => 3,
129-
Trap::IndirectCallToNull => 4,
130-
Trap::BadSignature => 5,
131-
Trap::IntegerOverflow => 6,
132-
Trap::IntegerDivisionByZero => 7,
133-
Trap::BadConversionToInteger => 8,
134-
Trap::UnreachableCodeReached => 9,
135-
Trap::Interrupt => 10,
136-
Trap::OutOfFuel => 11,
137-
Trap::AlwaysTrapAdapter => unreachable!("component model not supported"),
138-
_ => unreachable!(),
139-
};
132+
*code = *trap as u8;
140133
true
141134
}
142135

crates/c-api/tests/trap.cc

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,46 @@ TEST(Trap, Smoke) {
2929
for (auto &frame : trace) {
3030
}
3131

32-
EXPECT_TRUE(func.call(store, {}).err().message().find("unreachable") !=
32+
auto unreachable_trap = std::get<Trap>(func.call(store, {}).err().data);
33+
34+
EXPECT_EQ(unreachable_trap.code(),
35+
WASMTIME_TRAP_CODE_UNREACHABLE_CODE_REACHED);
36+
EXPECT_TRUE(unreachable_trap.message().find("unreachable") !=
3337
std::string::npos);
3438
EXPECT_EQ(func.call(store, {1}).err().message(),
3539
"expected 0 arguments, got 1");
40+
41+
Trap out_of_fuel(WASMTIME_TRAP_CODE_OUT_OF_FUEL);
42+
EXPECT_EQ(out_of_fuel.code(), WASMTIME_TRAP_CODE_OUT_OF_FUEL);
43+
EXPECT_TRUE(out_of_fuel.message().find("all fuel consumed") !=
44+
std::string::npos);
45+
}
46+
47+
TEST(Trap, Codes) {
48+
#define TEST_CODE(trapcode) \
49+
EXPECT_EQ(Trap(WASMTIME_TRAP_CODE_##trapcode).code(), \
50+
WASMTIME_TRAP_CODE_##trapcode);
51+
52+
TEST_CODE(STACK_OVERFLOW);
53+
TEST_CODE(MEMORY_OUT_OF_BOUNDS);
54+
TEST_CODE(HEAP_MISALIGNED);
55+
TEST_CODE(TABLE_OUT_OF_BOUNDS);
56+
TEST_CODE(INDIRECT_CALL_TO_NULL);
57+
TEST_CODE(BAD_SIGNATURE);
58+
TEST_CODE(INTEGER_OVERFLOW);
59+
TEST_CODE(INTEGER_DIVISION_BY_ZERO);
60+
TEST_CODE(BAD_CONVERSION_TO_INTEGER);
61+
TEST_CODE(UNREACHABLE_CODE_REACHED);
62+
TEST_CODE(INTERRUPT);
63+
TEST_CODE(ALWAYS_TRAP_ADAPTER);
64+
TEST_CODE(OUT_OF_FUEL);
65+
TEST_CODE(ATOMIC_WAIT_NON_SHARED_MEMORY);
66+
TEST_CODE(NULL_REFERENCE);
67+
TEST_CODE(ARRAY_OUT_OF_BOUNDS);
68+
TEST_CODE(ALLOCATION_TOO_LARGE);
69+
TEST_CODE(CAST_FAILURE);
70+
TEST_CODE(CANNOT_ENTER_COMPONENT);
71+
TEST_CODE(NO_ASYNC_RESULT);
72+
TEST_CODE(DISABLED_OPCODE);
73+
#undef TEST_CODE
3674
}

0 commit comments

Comments
 (0)