Remove unsafety from Trap API (#779)

* Remove unsafety from `Trap` API

This commit removes the `unsafe impl Send` for `Trap` by removing the
internal `HostRef` and leaving `HostRef` entirely as an implementation
detail of the C API.

cc #708

* Run rustfmt
This commit is contained in:
Alex Crichton
2020-01-08 14:41:47 -06:00
committed by GitHub
parent 06be4b1495
commit c975a92a3a
9 changed files with 86 additions and 130 deletions

View File

@@ -1,8 +1,65 @@
use crate::instance::Instance;
use crate::r#ref::HostRef;
use std::fmt;
use std::sync::{Arc, Mutex};
use thiserror::Error;
use std::sync::Arc;
/// A struct representing an aborted instruction execution, with a message
/// indicating the cause.
#[derive(Clone)]
pub struct Trap {
inner: Arc<TrapInner>,
}
struct TrapInner {
message: String,
trace: Vec<FrameInfo>,
}
fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
(t, t)
}
impl Trap {
/// Creates a new `Trap` with `message`.
/// # Example
/// ```
/// let trap = wasmtime::Trap::new("unexpected error");
/// assert_eq!("unexpected error", trap.message());
/// ```
pub fn new<I: Into<String>>(message: I) -> Self {
Trap {
inner: Arc::new(TrapInner {
message: message.into(),
trace: Vec::new(),
}),
}
}
/// Returns a reference the `message` stored in `Trap`.
pub fn message(&self) -> &str {
&self.inner.message
}
pub fn trace(&self) -> &[FrameInfo] {
&self.inner.trace
}
}
impl fmt::Debug for Trap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Trap")
.field("message", &self.inner.message)
.field("trace", &self.inner.trace)
.finish()
}
}
impl fmt::Display for Trap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.message.fmt(f)
}
}
impl std::error::Error for Trap {}
#[derive(Debug)]
pub struct FrameInfo;
@@ -24,94 +81,3 @@ impl FrameInfo {
unimplemented!("FrameInfo::module_offset");
}
}
#[derive(Debug)]
pub struct TrapInfo {
message: String,
trace: Vec<FrameInfo>,
}
impl TrapInfo {
pub fn new<I: Into<String>>(message: I) -> Self {
Self {
message: message.into(),
trace: vec![],
}
}
/// Returns a reference the `message` stored in `Trap`.
pub fn message(&self) -> &str {
&self.message
}
pub fn origin(&self) -> Option<&FrameInfo> {
self.trace.first()
}
pub fn trace(&self) -> &[FrameInfo] {
&self.trace
}
}
/// A struct to hold unsafe TrapInfo host reference, designed
/// to be Send-able. The only access for it provided via the
/// Trap::trap_info_unchecked() method.
struct UnsafeTrapInfo(HostRef<TrapInfo>);
impl UnsafeTrapInfo {
fn trap_info(&self) -> HostRef<TrapInfo> {
self.0.clone()
}
}
unsafe impl Send for UnsafeTrapInfo {}
impl fmt::Debug for UnsafeTrapInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UnsafeTrapInfo")
}
}
/// A struct representing an aborted instruction execution, with a message
/// indicating the cause.
#[derive(Error, Debug, Clone)]
#[error("Wasm trap: {message}")]
pub struct Trap {
message: String,
info: Arc<Mutex<UnsafeTrapInfo>>,
}
fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
(t, t)
}
impl Trap {
/// Creates a new `Trap` with `message`.
/// # Example
/// ```
/// let trap = wasmtime::Trap::new("unexpected error");
/// assert_eq!("unexpected error", trap.message());
/// ```
pub fn new<I: Into<String>>(message: I) -> Self {
Trap::from(HostRef::new(TrapInfo::new(message)))
}
/// Returns a reference the `message` stored in `Trap`.
pub fn message(&self) -> &str {
&self.message
}
/// Returns inner TrapInfo assotiated with the Trap.
/// The method is unsafe: obtained TrapInfo is not thread safe.
pub(crate) unsafe fn trap_info_unchecked(&self) -> HostRef<TrapInfo> {
self.info.lock().unwrap().trap_info()
}
}
impl From<HostRef<TrapInfo>> for Trap {
fn from(trap_info: HostRef<TrapInfo>) -> Self {
let message = trap_info.borrow().message().to_string();
let info = Arc::new(Mutex::new(UnsafeTrapInfo(trap_info)));
Trap { message, info }
}
}