Skip to content

Commit 60cd084

Browse files
committed
Keep module data alive for the lifetime of the runtime
1 parent 3d04e0f commit 60cd084

File tree

5 files changed

+37
-18
lines changed

5 files changed

+37
-18
lines changed

src/environment.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
use alloc::boxed::Box;
12
use alloc::rc::Rc;
3+
24
use core::ptr::NonNull;
35

46
use crate::error::{Error, Result};
@@ -43,7 +45,7 @@ impl Environment {
4345

4446
/// Parses a wasm module from raw bytes.
4547
#[inline]
46-
pub fn parse_module(&self, bytes: &[u8]) -> Result<ParsedModule> {
48+
pub fn parse_module<TData: Into<Box<[u8]>>>(&self, bytes: TData) -> Result<ParsedModule> {
4749
ParsedModule::parse(self, bytes)
4850
}
4951

src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#![cfg_attr(not(feature = "std"), no_std)]
22
#![warn(missing_docs)]
3-
#![warn(clippy::all)]
4-
#![allow(clippy::match_bool)]
53
//! A rust wrapper for [WASM3](https://github.com/wasm3/wasm3).
64
75
extern crate alloc;

src/module.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use alloc::boxed::Box;
2+
3+
use core::mem;
24
use core::ptr::{self, NonNull};
35
use core::slice;
46

@@ -11,24 +13,22 @@ use crate::wasm3_priv;
1113

1214
/// A parsed module which can be loaded into a [`Runtime`].
1315
pub struct ParsedModule {
16+
data: Box<[u8]>,
1417
raw: ffi::IM3Module,
1518
env: Environment,
1619
}
1720

1821
impl ParsedModule {
1922
/// Parses a wasm module from raw bytes.
20-
pub fn parse(env: &Environment, bytes: &[u8]) -> Result<Self> {
21-
assert!(bytes.len() <= !0u32 as usize);
23+
pub fn parse<TData: Into<Box<[u8]>>>(env: &Environment, data: TData) -> Result<Self> {
24+
let data = data.into();
25+
assert!(data.len() <= !0u32 as usize);
2226
let mut module = ptr::null_mut();
2327
let res = unsafe {
24-
ffi::m3_ParseModule(
25-
env.as_ptr(),
26-
&mut module,
27-
bytes.as_ptr(),
28-
bytes.len() as u32,
29-
)
28+
ffi::m3_ParseModule(env.as_ptr(), &mut module, data.as_ptr(), data.len() as u32)
3029
};
3130
Error::from_ffi_res(res).map(|_| ParsedModule {
31+
data,
3232
raw: module,
3333
env: env.clone(),
3434
})
@@ -38,6 +38,12 @@ impl ParsedModule {
3838
self.raw
3939
}
4040

41+
pub(crate) fn take_data(self) -> Box<[u8]> {
42+
let res = unsafe { ptr::read(&self.data) };
43+
mem::forget(self);
44+
res
45+
}
46+
4147
/// The environment this module was parsed in.
4248
pub fn environment(&self) -> &Environment {
4349
&self.env
@@ -60,7 +66,10 @@ pub struct Module<'rt> {
6066
impl<'rt> Module<'rt> {
6167
/// Parses a wasm module from raw bytes.
6268
#[inline]
63-
pub fn parse(environment: &Environment, bytes: &[u8]) -> Result<ParsedModule> {
69+
pub fn parse<TData: Into<Box<[u8]>>>(
70+
environment: &Environment,
71+
bytes: TData,
72+
) -> Result<ParsedModule> {
6473
ParsedModule::parse(environment, bytes)
6574
}
6675

src/runtime.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub struct Runtime {
2020
environment: Environment,
2121
// holds all linked closures so that they properly get disposed of when runtime drops
2222
closure_store: UnsafeCell<Vec<PinnedAnyClosure>>,
23+
// holds all backing data of loaded modules as they have to be kept alive for the module's lifetime
24+
module_data: UnsafeCell<Vec<Box<[u8]>>>,
2325
}
2426

2527
impl Runtime {
@@ -41,11 +43,15 @@ impl Runtime {
4143
raw,
4244
environment: environment.clone(),
4345
closure_store: UnsafeCell::new(Vec::new()),
46+
module_data: UnsafeCell::new(Vec::new()),
4447
})
4548
}
4649

4750
/// Parses and loads a module from bytes.
48-
pub fn parse_and_load_module<'rt>(&'rt self, bytes: &[u8]) -> Result<Module<'rt>> {
51+
pub fn parse_and_load_module<'rt, TData: Into<Box<[u8]>>>(
52+
&'rt self,
53+
bytes: TData,
54+
) -> Result<Module<'rt>> {
4955
Module::parse(&self.environment, bytes).and_then(|module| self.load_module(module))
5056
}
5157

@@ -58,10 +64,13 @@ impl Runtime {
5864
if &self.environment != module.environment() {
5965
Err(Error::ModuleLoadEnvMismatch)
6066
} else {
61-
Error::from_ffi_res(unsafe { ffi::m3_LoadModule(self.raw.as_ptr(), module.as_ptr()) })?;
62-
let raw = module.as_ptr();
63-
mem::forget(module);
64-
Ok(Module::from_raw(self, raw))
67+
let raw_mod = module.as_ptr();
68+
Error::from_ffi_res(unsafe { ffi::m3_LoadModule(self.raw.as_ptr(), raw_mod) })?;
69+
// SAFETY: Runtime isn't Send, therefor this access is single-threaded and kept alive only for the Vec::push call
70+
// as such this can not alias.
71+
unsafe { (*self.module_data.get()).push(module.take_data()) };
72+
73+
Ok(Module::from_raw(self, raw_mod))
6574
}
6675
}
6776

@@ -76,7 +85,7 @@ impl Runtime {
7685
{
7786
self.modules()
7887
.find_map(|module| match module.find_function::<ARGS, RET>(name) {
79-
res @ Ok(_) | res @ Err(Error::InvalidFunctionSignature) => Some(res),
88+
res @ (Ok(_) | Err(Error::InvalidFunctionSignature)) => Some(res),
8089
_ => None,
8190
})
8291
.unwrap_or(Err(Error::FunctionNotFound))

wasm3-sys/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
#![allow(non_upper_case_globals)]
33
#![allow(non_camel_case_types)]
44
#![allow(non_snake_case)]
5+
#![allow(clippy::all)]
56

67
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

0 commit comments

Comments
 (0)