mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 22:09:09 +00:00
wasm: tests read panic message from a global pointer
This commit is contained in:
parent
4e7c1fe5e1
commit
8d484e8c9e
2 changed files with 19 additions and 46 deletions
|
@ -1,6 +1,8 @@
|
|||
use core::cell::Cell;
|
||||
use libc::c_char;
|
||||
use roc_gen_wasm::wasm_module::{Export, ExportType};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::ffi::CStr;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -17,7 +19,7 @@ const OUT_DIR_VAR: &str = "TEST_GEN_OUT";
|
|||
|
||||
const TEST_WRAPPER_NAME: &str = "test_wrapper";
|
||||
const INIT_REFCOUNT_NAME: &str = "init_refcount_test";
|
||||
const GET_PANIC_MSG_NAME: &str = "get_panic_msg";
|
||||
const PANIC_MSG_NAME: &str = "panic_msg";
|
||||
|
||||
fn promote_expr_to_module(src: &str) -> String {
|
||||
let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
|
||||
|
@ -135,15 +137,6 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32Result>(
|
|||
index: init_refcount_idx,
|
||||
});
|
||||
|
||||
// Export the getter function for panic messages
|
||||
let get_panic_msg_bytes = GET_PANIC_MSG_NAME.as_bytes();
|
||||
let get_panic_msg_idx = module.names.functions[get_panic_msg_bytes];
|
||||
module.export.append(Export {
|
||||
name: arena.alloc_slice_copy(get_panic_msg_bytes),
|
||||
ty: ExportType::Func,
|
||||
index: get_panic_msg_idx,
|
||||
});
|
||||
|
||||
module.remove_dead_preloads(env.arena, called_preload_fns);
|
||||
|
||||
let mut app_module_bytes = std::vec::Vec::with_capacity(module.size());
|
||||
|
@ -202,10 +195,22 @@ where
|
|||
let test_wrapper = instance.exports.get_function(TEST_WRAPPER_NAME).unwrap();
|
||||
|
||||
match test_wrapper.call(&[]) {
|
||||
Err(e) => match get_panic_msg(&instance, memory) {
|
||||
Ok(msg) => Err(msg),
|
||||
Err(_) => Err(format!("{}", e)),
|
||||
},
|
||||
Err(e) => {
|
||||
// Check if the error is from roc_panic
|
||||
// Our test roc_panic stores a pointer to its message in a global variable so we can find it.
|
||||
let panic_msg_global = instance.exports.get_global(PANIC_MSG_NAME).unwrap();
|
||||
let panic_msg_index = panic_msg_global.get().unwrap_i32() as usize;
|
||||
if panic_msg_index == 0 {
|
||||
// Pointer is null. The error isn't a roc_panic.
|
||||
Err(e.to_string())
|
||||
} else {
|
||||
let memory_bytes = unsafe { memory.data_unchecked() };
|
||||
let msg_ptr = memory_bytes[panic_msg_index..].as_ptr() as *const c_char;
|
||||
let msg_cstr = unsafe { CStr::from_ptr(msg_ptr) };
|
||||
let msg_str = msg_cstr.to_str().unwrap();
|
||||
Err(msg_str.into())
|
||||
}
|
||||
}
|
||||
Ok(result) => {
|
||||
let address = result[0].unwrap_i32();
|
||||
|
||||
|
@ -226,35 +231,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Call our test platform's getter function for panic messages
|
||||
fn get_panic_msg(instance: &wasmer::Instance, memory: &wasmer::Memory) -> Result<String, String> {
|
||||
let msg_getter = instance
|
||||
.exports
|
||||
.get_function(GET_PANIC_MSG_NAME)
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
|
||||
let msg_result = msg_getter.call(&[]).map_err(|e| format!("{:?}", e))?;
|
||||
|
||||
let msg_addr: i32 = match msg_result[0] {
|
||||
wasmer::Value::I32(a) => a,
|
||||
_ => panic!(),
|
||||
};
|
||||
if msg_addr == 0 {
|
||||
return Err("no panic msg".to_string());
|
||||
}
|
||||
|
||||
let msg_index = msg_addr as usize;
|
||||
let memory_bytes = unsafe { memory.data_unchecked() };
|
||||
let msg_len = memory_bytes[msg_index..]
|
||||
.iter()
|
||||
.position(|c| *c == 0)
|
||||
.unwrap();
|
||||
|
||||
let msg_bytes = &memory_bytes[msg_index..msg_len];
|
||||
let msg = unsafe { String::from_utf8_unchecked(msg_bytes.to_vec()) };
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn assert_wasm_refcounts_help<T>(
|
||||
src: &str,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue