Make runtime and trap errors well defined (WIP)

This commit is contained in:
Mark McCaskey
2020-04-23 12:40:35 -07:00
parent ab106af422
commit bfb6814f23
6 changed files with 125 additions and 35 deletions

View File

@ -1,12 +1,13 @@
use crate::{
relocation::{TrapData, TrapSink},
relocation::{TrapData, TrapSink, TrapCode},
resolver::FuncResolver,
trampoline::Trampolines,
};
use libc::c_void;
use std::{any::Any, cell::Cell, ptr::NonNull, sync::Arc};
use wasmer_runtime_core::{
backend::RunnableModule,
backend::{RunnableModule, ExceptionCode},
error::{InvokeError, RuntimeError},
module::ModuleInfo,
typed_func::{Trampoline, Wasm},
types::{LocalFuncIndex, SigIndex},
@ -26,10 +27,25 @@ pub use self::unix::*;
pub use self::windows::*;
thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any + Send>>> = Cell::new(None);
pub static TRAP_EARLY_DATA: Cell<Option<RuntimeError>> = Cell::new(None);
}
pub struct CallProtError(pub Box<dyn Any + Send>);
pub enum CallProtError {
UnknownTrap {
address: usize,
signal: &'static str,
},
TrapCode {
code: ExceptionCode,
srcloc: u32,
},
UnknownTrapCode {
trap_code: TrapCode,
srcloc: u32,
},
EarlyTrap(RuntimeError),
Misc(Box<dyn Any + Send>),
}
pub struct Caller {
handler_data: HandlerData,
@ -63,7 +79,7 @@ impl RunnableModule for Caller {
func: NonNull<vm::Func>,
args: *const u64,
rets: *mut u64,
error_out: *mut Option<Box<dyn Any + Send>>,
error_out: *mut Option<InvokeError>,
invoke_env: Option<NonNull<c_void>>,
) -> bool {
let handler_data = &*invoke_env.unwrap().cast().as_ptr();
@ -80,6 +96,9 @@ impl RunnableModule for Caller {
match res {
Err(err) => {
// probably makes the most sense to actually do a translation here to a
// a generic type defined in runtime-core
// TODO: figure out _this_ error return story
*error_out = Some(err.0);
false
}
@ -101,7 +120,7 @@ impl RunnableModule for Caller {
})
}
unsafe fn do_early_trap(&self, data: Box<dyn Any + Send>) -> ! {
unsafe fn do_early_trap(&self, data: RuntimeError) -> ! {
TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
trigger_trap()
}

View File

@ -79,16 +79,16 @@ pub fn call_protected<T>(
*jmp_buf = prev_jmp_buf;
if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
Err(CallProtError(data))
Err(CallProtError::EarlyTrap(data))
} else {
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
if let Some(TrapData {
trapcode,
srcloc: _,
srcloc,
}) = handler_data.lookup(inst_ptr)
{
Err(CallProtError(Box::new(match Signal::from_c_int(signum) {
let code = match Signal::from_c_int(signum) {
Ok(SIGILL) => match trapcode {
TrapCode::StackOverflow => ExceptionCode::MemoryOutOfBounds,
TrapCode::HeapOutOfBounds => ExceptionCode::MemoryOutOfBounds,
@ -101,9 +101,10 @@ pub fn call_protected<T>(
TrapCode::BadConversionToInteger => ExceptionCode::IllegalArithmetic,
TrapCode::UnreachableCodeReached => ExceptionCode::Unreachable,
_ => {
return Err(CallProtError(Box::new(
"unknown clif trap code".to_string(),
)))
return Err(CallProtError::UnknownTrapCode {
trap_code: trapcode,
srcloc,
})
}
},
Ok(SIGSEGV) | Ok(SIGBUS) => ExceptionCode::MemoryOutOfBounds,
@ -112,7 +113,11 @@ pub fn call_protected<T>(
"ExceptionCode::Unknown signal:{:?}",
Signal::from_c_int(signum)
),
})))
};
Err(CallProtError::TrapCode {
srcloc,
code,
})
} else {
let signal = match Signal::from_c_int(signum) {
Ok(SIGFPE) => "floating-point exception",
@ -123,8 +128,10 @@ pub fn call_protected<T>(
_ => "unknown trapped signal",
};
// When the trap-handler is fully implemented, this will return more information.
let s = format!("unknown trap at {:p} - {}", faulting_addr, signal);
Err(CallProtError(Box::new(s)))
Err(CallProtError::UnknownTrap {
address: faulting_addr as usize,
signal,
})
}
}
} else {