diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
commit | d1b2d29528b7794b41e66fc2136e395a02f8529b (patch) | |
tree | a4a17504b260206dec3cf55b2dca82929a348ac2 /tests/run-make/wasm-exceptions-nostd | |
parent | Releasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-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/Makefile | 12 | ||||
-rw-r--r-- | tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs | 67 | ||||
-rw-r--r-- | tests/run-make/wasm-exceptions-nostd/src/lib.rs | 60 | ||||
-rw-r--r-- | tests/run-make/wasm-exceptions-nostd/src/logging.rs | 9 | ||||
-rw-r--r-- | tests/run-make/wasm-exceptions-nostd/src/panicking.rs | 29 | ||||
-rw-r--r-- | tests/run-make/wasm-exceptions-nostd/verify.mjs | 75 |
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 |