wasm: tests read panic message from a global pointer

This commit is contained in:
Brian Carroll 2022-02-28 00:53:01 +00:00
parent 4e7c1fe5e1
commit 8d484e8c9e
2 changed files with 19 additions and 46 deletions

View file

@ -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,

View file

@ -124,9 +124,6 @@ void roc_dealloc(void *ptr, unsigned int alignment)
// Allow the test to probe the panic message
char* panic_msg;
char* get_panic_msg() {
return panic_msg;
}
void roc_panic(char *msg, unsigned int tag_id)
{