summaryrefslogtreecommitdiffstats
path: root/tests/run-make/wasm-exceptions-nostd
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /tests/run-make/wasm-exceptions-nostd
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/run-make/wasm-exceptions-nostd')
-rw-r--r--tests/run-make/wasm-exceptions-nostd/Makefile12
-rw-r--r--tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs67
-rw-r--r--tests/run-make/wasm-exceptions-nostd/src/lib.rs60
-rw-r--r--tests/run-make/wasm-exceptions-nostd/src/logging.rs9
-rw-r--r--tests/run-make/wasm-exceptions-nostd/src/panicking.rs29
-rw-r--r--tests/run-make/wasm-exceptions-nostd/verify.mjs75
6 files changed, 252 insertions, 0 deletions
diff --git a/tests/run-make/wasm-exceptions-nostd/Makefile b/tests/run-make/wasm-exceptions-nostd/Makefile
new file mode 100644
index 000000000..34755ec14
--- /dev/null
+++ b/tests/run-make/wasm-exceptions-nostd/Makefile
@@ -0,0 +1,12 @@
+include ../tools.mk
+
+# only-wasm32-bare
+
+# Add a few command line args to make exceptions work
+RUSTC := $(RUSTC) -C llvm-args=-wasm-enable-eh
+RUSTC := $(RUSTC) -C target-feature=+exception-handling
+RUSTC := $(RUSTC) -C panic=unwind
+
+all:
+ $(RUSTC) src/lib.rs --target wasm32-unknown-unknown
+ $(NODE) verify.mjs $(TMPDIR)/lib.wasm
diff --git a/tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs b/tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs
new file mode 100644
index 000000000..572d25330
--- /dev/null
+++ b/tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs
@@ -0,0 +1,67 @@
+use core::alloc::{GlobalAlloc, Layout};
+use core::cell::UnsafeCell;
+
+#[global_allocator]
+static ALLOCATOR: ArenaAllocator = ArenaAllocator::new();
+
+/// Very simple allocator which never deallocates memory
+///
+/// Based on the example from
+/// https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html
+pub struct ArenaAllocator {
+ arena: UnsafeCell<Arena>,
+}
+
+impl ArenaAllocator {
+ pub const fn new() -> Self {
+ Self {
+ arena: UnsafeCell::new(Arena::new()),
+ }
+ }
+}
+
+/// Safe because we are singlethreaded
+unsafe impl Sync for ArenaAllocator {}
+
+unsafe impl GlobalAlloc for ArenaAllocator {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ let arena = &mut *self.arena.get();
+ arena.alloc(layout)
+ }
+
+ unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+}
+
+const ARENA_SIZE: usize = 64 * 1024; // more than enough
+
+#[repr(C, align(4096))]
+struct Arena {
+ buf: [u8; ARENA_SIZE], // aligned at 4096
+ allocated: usize,
+}
+
+impl Arena {
+ pub const fn new() -> Self {
+ Self {
+ buf: [0x55; ARENA_SIZE],
+ allocated: 0,
+ }
+ }
+
+ pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
+ if layout.align() > 4096 || layout.size() > ARENA_SIZE {
+ return core::ptr::null_mut();
+ }
+
+ let align_minus_one = layout.align() - 1;
+ let start = (self.allocated + align_minus_one) & !align_minus_one; // round up
+ let new_cursor = start + layout.size();
+
+ if new_cursor >= ARENA_SIZE {
+ return core::ptr::null_mut();
+ }
+
+ self.allocated = new_cursor;
+ self.buf.as_mut_ptr().add(start)
+ }
+}
diff --git a/tests/run-make/wasm-exceptions-nostd/src/lib.rs b/tests/run-make/wasm-exceptions-nostd/src/lib.rs
new file mode 100644
index 000000000..7049d2fd9
--- /dev/null
+++ b/tests/run-make/wasm-exceptions-nostd/src/lib.rs
@@ -0,0 +1,60 @@
+#![no_std]
+#![crate_type = "cdylib"]
+
+// Allow a few unstable features because we create a panic
+// runtime for native wasm exceptions from scratch
+
+#![feature(core_intrinsics)]
+#![feature(lang_items)]
+#![feature(link_llvm_intrinsics)]
+#![feature(panic_info_message)]
+
+extern crate alloc;
+
+/// This module allows us to use `Box`, `String`, ... even in no-std
+mod arena_alloc;
+
+/// This module allows logging text, even in no-std
+mod logging;
+
+/// This module allows exceptions, even in no-std
+#[cfg(target_arch = "wasm32")]
+mod panicking;
+
+use alloc::boxed::Box;
+use alloc::string::String;
+
+struct LogOnDrop;
+
+impl Drop for LogOnDrop {
+ fn drop(&mut self) {
+ logging::log_str("Dropped");
+ }
+}
+
+#[allow(unreachable_code)]
+#[allow(unconditional_panic)]
+#[no_mangle]
+pub extern "C" fn start() -> usize {
+ let data = 0x1234usize as *mut u8; // Something to recognize
+
+ unsafe {
+ core::intrinsics::r#try(|data: *mut u8| {
+ let _log_on_drop = LogOnDrop;
+
+ logging::log_str(&alloc::format!("`r#try` called with ptr {:?}", data));
+ let x = [12];
+ let _ = x[4]; // should panic
+
+ logging::log_str("This line should not be visible! :(");
+ }, data, |data, exception| {
+ let exception = *Box::from_raw(exception as *mut String);
+ logging::log_str("Caught something!");
+ logging::log_str(&alloc::format!(" data : {:?}", data));
+ logging::log_str(&alloc::format!(" exception: {:?}", exception));
+ });
+ }
+
+ logging::log_str("This program terminates correctly.");
+ 0
+}
diff --git a/tests/run-make/wasm-exceptions-nostd/src/logging.rs b/tests/run-make/wasm-exceptions-nostd/src/logging.rs
new file mode 100644
index 000000000..569d03ec8
--- /dev/null
+++ b/tests/run-make/wasm-exceptions-nostd/src/logging.rs
@@ -0,0 +1,9 @@
+extern "C" {
+ fn __log_utf8(ptr: *const u8, size: usize);
+}
+
+pub fn log_str(text: &str) {
+ unsafe {
+ __log_utf8(text.as_ptr(), text.len());
+ }
+}
diff --git a/tests/run-make/wasm-exceptions-nostd/src/panicking.rs b/tests/run-make/wasm-exceptions-nostd/src/panicking.rs
new file mode 100644
index 000000000..4a8923fd4
--- /dev/null
+++ b/tests/run-make/wasm-exceptions-nostd/src/panicking.rs
@@ -0,0 +1,29 @@
+#[lang = "eh_personality"]
+fn eh_personality() {}
+
+mod internal {
+ extern "C" {
+ #[link_name = "llvm.wasm.throw"]
+ pub fn wasm_throw(tag: i32, ptr: *mut u8) -> !;
+ }
+}
+
+unsafe fn wasm_throw(ptr: *mut u8) -> ! {
+ internal::wasm_throw(0, ptr);
+}
+
+#[panic_handler]
+fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
+ use alloc::boxed::Box;
+ use alloc::string::ToString;
+
+ let msg = info
+ .message()
+ .map(|msg| msg.to_string())
+ .unwrap_or("(no message)".to_string());
+ let exception = Box::new(msg.to_string());
+ unsafe {
+ let exception_raw = Box::into_raw(exception);
+ wasm_throw(exception_raw as *mut u8);
+ }
+}
diff --git a/tests/run-make/wasm-exceptions-nostd/verify.mjs b/tests/run-make/wasm-exceptions-nostd/verify.mjs
new file mode 100644
index 000000000..e6c44d89d
--- /dev/null
+++ b/tests/run-make/wasm-exceptions-nostd/verify.mjs
@@ -0,0 +1,75 @@
+import fs from 'fs';
+
+const dec = new TextDecoder("utf-8");
+
+if (process.argv.length != 3) {
+ console.log("Usage: node verify.mjs <wasm-file>");
+ process.exit(0);
+}
+
+const wasmfile = process.argv[2];
+if (!fs.existsSync(wasmfile)) {
+ console.log("Error: File not found:", wasmfile);
+ process.exit(1);
+}
+
+const wasmBuffer = fs.readFileSync(wasmfile);
+
+async function main() {
+
+ let memory = new ArrayBuffer(0) // will be changed after instantiate
+
+ const captured_output = [];
+
+ const imports = {
+ env: {
+ __log_utf8: (ptr, size) => {
+ const str = dec.decode(new DataView(memory, ptr, size));
+ captured_output.push(str);
+ console.log(str);
+ }
+ }
+ };
+
+ const wasmModule = await WebAssembly.instantiate(wasmBuffer, imports);
+ memory = wasmModule.instance.exports.memory.buffer;
+
+ const start = wasmModule.instance.exports.start;
+ const return_code = start();
+
+ console.log("Return-Code:", return_code);
+
+ if (return_code !== 0) {
+ console.error("Expected return code 0");
+ process.exit(return_code);
+ }
+
+ const expected_output = [
+ '`r#try` called with ptr 0x1234',
+ 'Dropped',
+ 'Caught something!',
+ ' data : 0x1234',
+ ' exception: "index out of bounds: the len is 1 but the index is 4"',
+ 'This program terminates correctly.',
+ ];
+
+ assert_equal(captured_output, expected_output);
+}
+
+function assert_equal(captured_output, expected_output) {
+ if (captured_output.length != expected_output.length) {
+ console.error("Unexpected number of output lines. Got", captured_output.length, "but expected", expected_output.length);
+ process.exit(1); // exit with error
+ }
+
+ for (let idx = 0; idx < expected_output.length; ++idx) {
+ if (captured_output[idx] !== expected_output[idx]) {
+ console.error("Unexpected output");
+ console.error("[got] ", captured_output[idx]);
+ console.error("[expected]", expected_output[idx]);
+ process.exit(2); // exit with error
+ }
+ }
+}
+
+await main(); \ No newline at end of file