Compare commits

..

13 Commits

Author SHA1 Message Date
zach
24622cd511 wip 2024-06-14 18:52:50 -07:00
zach
00f9155b9e feat: switch to owi conc, avoid needing wasm2wat 2024-06-14 18:46:27 -07:00
zach
7c770e2f1c feat(kernel): add proof for error handling 2024-06-14 18:46:27 -07:00
zach
33ad239c50 wip: reuse proof 2024-06-14 18:46:27 -07:00
zach
a62e37c21b cleanup: reduce the size of the allocation used in load_store example 2024-06-14 18:46:27 -07:00
zach
20ee6620c6 cleanup: improve verification 2024-06-14 18:46:27 -07:00
zach
db0b04696c cleanup: move proofs to examples directory 2024-06-14 18:46:27 -07:00
zach
6cc22bf2de cleanup: use new names from owi 2024-06-14 18:46:11 -07:00
zach
52d3c4ffd6 cleanup: add some comments to verification tests 2024-06-14 18:46:11 -07:00
zach
b96b28231f cleanup: ignore verification artifacts 2024-06-14 18:46:11 -07:00
zach
c1180d576c checkpoint: use owi crate from git 2024-06-14 18:46:11 -07:00
zach
48af68facc cleanup: improve owi verification 2024-06-14 18:46:11 -07:00
zach
38e6476797 wip 2024-06-14 18:46:09 -07:00
27 changed files with 272 additions and 323 deletions

View File

@@ -81,10 +81,10 @@ mod tests {
c: true,
};
let raw = Raw(&x).to_bytes().unwrap();
let y = Raw::from_bytes(raw).unwrap();
let y = Raw::from_bytes(&raw).unwrap();
assert_eq!(&x, y.0);
let y: Result<Raw<[u8; std::mem::size_of::<TestRaw>()]>, Error> = Raw::from_bytes(raw);
let y: Result<Raw<[u8; std::mem::size_of::<TestRaw>()]>, Error> = Raw::from_bytes(&raw);
assert!(y.is_ok());
}
}

3
kernel/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
owi-out
*.wat
proofs

View File

@@ -7,6 +7,7 @@ edition = "2021"
[dev-dependencies]
wasm-bindgen-test = "0.3.39"
owi = {git = "https://github.com/dylibso/owi-rs"}
[features]
default = ["bounds-checking"]
@@ -15,4 +16,4 @@ bounds-checking = []
[workspace]
members = [
"."
]
]

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env bash
set -e
export CARGO_FLAGS=""
while getopts d flag

View File

@@ -0,0 +1,21 @@
#![no_main]
#![no_std]
use extism_runtime_kernel::*;
use owi::*;
main!({
let n = alloc(1024);
let x = u64();
assume(x > 0);
let m = alloc(x);
// 1. Length should equal `x` while active
assert(length(m) == x);
// 2. Length should equal `0` after free
free(m); // Free the block
assert(length(m) == 0);
free(n);
});

24
kernel/examples/error.rs Normal file
View File

@@ -0,0 +1,24 @@
#![no_main]
#![no_std]
use extism_runtime_kernel::*;
use owi::*;
main!({
let x = u64();
let n = u64();
let m = u64();
assume(x > 0);
assume(n > 0);
assume(m > 0);
alloc(n);
alloc(m);
let n = alloc(x);
assert(error_get() == 0);
error_set(n);
assert(error_get() == n);
alloc(m);
error_set(0);
assert(error_get() == 0);
});

View File

@@ -0,0 +1,17 @@
#![no_main]
#![no_std]
use extism_runtime_kernel::*;
use owi::*;
main!({
let x = u64();
assume(x > 0);
let m = alloc(x);
assert(length(m) == x);
for i in 0..x {
store_u8(m + i, i as u8);
assert(load_u8(m + i) == i as u8);
}
free(m);
});

39
kernel/examples/reuse.rs Normal file
View File

@@ -0,0 +1,39 @@
#![no_main]
#![no_std]
use extism_runtime_kernel::*;
use owi::*;
main!({
let x = u64();
assume(x > 0);
let y = u64();
assume(y > 0);
let mut tmp = 0;
for _ in 0..y {
let m = alloc(x);
if tmp == 0 {
tmp = m;
} else {
// Check that the existing block is being re-used
assert(m == tmp);
}
assert(length(m) == x);
free(m); // Free the block
}
let y = u64();
assume(y == x + 1);
let n = alloc(y);
assert(n > tmp);
let z = u64();
assume(z <= x);
assume(x - z < 32);
assume(z > 0);
let p = alloc(z);
assert(p == tmp);
});

View File

@@ -1,5 +1,5 @@
#![no_main]
#![no_std]
#![no_main]
pub use extism_runtime_kernel::*;

View File

@@ -175,7 +175,7 @@ impl MemoryRoot {
core::ptr::write_bytes(
self.blocks.as_mut_ptr() as *mut u8,
MemoryStatus::Unused as u8,
self_position as usize,
self_position as usize - core::mem::size_of::<MemoryRoot>(),
);
// Clear extism runtime metadata
@@ -546,8 +546,7 @@ pub unsafe fn reset() {
MemoryRoot::new().reset()
}
/// Set the error message offset, the handle passed to this
/// function should not be freed after this call
/// Set the error message offset
#[no_mangle]
pub unsafe fn error_set(h: Handle) {
let root = MemoryRoot::new();
@@ -639,4 +638,15 @@ mod test {
assert_eq!(last, 0);
}
#[wasm_bindgen_test]
fn test_sym() {
unsafe {
reset();
let a = alloc(47);
let b = alloc(20);
assert_eq!(length(a), 47);
assert_eq!(length(b), 20);
}
}
}

23
kernel/verify.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -e
OUT_DIR=./target/wasm32-unknown-unknown/release/examples/
get_proof() {
cp "$OUT_DIR/$1.wasm" "./proofs/$1.wasm"
}
cargo build --examples --release --target wasm32-unknown-unknown --no-default-features
mkdir -p proofs
get_proof alloc_length
get_proof load_store
get_proof reuse
get_proof error
for proof in $(ls proofs/*.wasm); do
echo "Checking $proof"
owi conc "$proof" $@
echo
echo "---"
done

View File

@@ -279,7 +279,7 @@ pub struct Manifest {
/// the path on disk to the path it should be available inside the plugin.
/// For example, `".": "/tmp"` would mount the current directory as `/tmp` inside the module
#[serde(default)]
pub allowed_paths: Option<BTreeMap<String, PathBuf>>,
pub allowed_paths: Option<BTreeMap<PathBuf, PathBuf>>,
/// The plugin timeout in milliseconds
#[serde(default)]
@@ -337,7 +337,8 @@ impl Manifest {
}
/// Add a path to `allowed_paths`
pub fn with_allowed_path(mut self, src: String, dest: impl AsRef<Path>) -> Self {
pub fn with_allowed_path(mut self, src: impl AsRef<Path>, dest: impl AsRef<Path>) -> Self {
let src = src.as_ref().to_path_buf();
let dest = dest.as_ref().to_path_buf();
match &mut self.allowed_paths {
Some(p) => {
@@ -354,7 +355,7 @@ impl Manifest {
}
/// Set `allowed_paths`
pub fn with_allowed_paths(mut self, paths: impl Iterator<Item = (String, PathBuf)>) -> Self {
pub fn with_allowed_paths(mut self, paths: impl Iterator<Item = (PathBuf, PathBuf)>) -> Self {
self.allowed_paths = Some(paths.collect());
self
}

View File

@@ -9,9 +9,8 @@ repository.workspace = true
version.workspace = true
[dependencies]
wasmtime = ">= 20.0.0, < 23.0.0"
wasi-common = ">= 20.0.0, < 23.0.0"
wiggle = ">= 20.0.0, < 23.0.0"
wasmtime = ">= 20.0.0, < 22.0.0"
wasi-common = ">= 20.0.0, < 22.0.0"
anyhow = "1"
serde = {version = "1", features = ["derive"]}
serde_json = "1"

View File

@@ -12,7 +12,7 @@ To use the `extism` crate, you can add it to your Cargo file:
```toml
[dependencies]
extism = "1.4.1"
extism = "1.2.0"
```
## Environment variables

View File

@@ -35,21 +35,6 @@ pub fn create_plugin(c: &mut Criterion) {
});
}
pub fn create_plugin_no_cache(c: &mut Criterion) {
let mut g = c.benchmark_group("create");
g.noise_threshold(1.0);
g.significance_level(0.2);
g.bench_function("create_plugin_no_cache", |b| {
b.iter(|| {
let _plugin = PluginBuilder::new(COUNT_VOWELS)
.with_cache_disabled()
.with_wasi(true)
.build()
.unwrap();
})
});
}
#[derive(Debug, serde::Deserialize, PartialEq)]
struct Count {
count: u32,
@@ -266,7 +251,6 @@ criterion_group!(
reflect_linked,
basic,
create_plugin,
create_plugin_no_cache,
count_vowels
);
criterion_main!(benches);

View File

@@ -1,33 +0,0 @@
use extism::*;
fn main() {
let url = Wasm::file("../wasm/read_write.wasm");
let manifest = Manifest::new([url])
.with_allowed_path("ro:src/tests/data".to_string(), "/data")
.with_config_key("path", "/data/data.txt");
let mut plugin = PluginBuilder::new(manifest)
.with_wasi(true)
.build()
.unwrap();
println!("trying to read file: ");
let res = plugin.call::<&str, &str>("try_read", "").unwrap();
println!("{:?}", res);
println!("-----------------------------------------------------");
println!("trying to write file: ");
let line = format!(
"Hello World at {:?}\n",
std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap()
);
let res2 = plugin.call::<&str, &str>("try_write", &line).unwrap();
println!("{:?}", res2);
println!("done!");
}

View File

@@ -160,10 +160,10 @@ impl CurrentPlugin {
}
pub fn memory_bytes_mut(&mut self, handle: MemoryHandle) -> Result<&mut [u8], Error> {
let (linker, store) = self.linker_and_store();
if let Some(mem) = linker.get(&mut *store, EXTISM_ENV_MODULE, "memory") {
let (linker, mut store) = self.linker_and_store();
if let Some(mem) = linker.get(&mut store, EXTISM_ENV_MODULE, "memory") {
let mem = mem.into_memory().unwrap();
let ptr = unsafe { mem.data_ptr(&*store).add(handle.offset() as usize) };
let ptr = unsafe { mem.data_ptr(&store).add(handle.offset() as usize) };
if ptr.is_null() {
return Ok(&mut []);
}
@@ -174,10 +174,10 @@ impl CurrentPlugin {
}
pub fn memory_bytes(&mut self, handle: MemoryHandle) -> Result<&[u8], Error> {
let (linker, store) = self.linker_and_store();
if let Some(mem) = linker.get(&mut *store, EXTISM_ENV_MODULE, "memory") {
let (linker, mut store) = self.linker_and_store();
if let Some(mem) = linker.get(&mut store, EXTISM_ENV_MODULE, "memory") {
let mem = mem.into_memory().unwrap();
let ptr = unsafe { mem.data_ptr(&*store).add(handle.offset() as usize) };
let ptr = unsafe { mem.data_ptr(&store).add(handle.offset() as usize) };
if ptr.is_null() {
return Ok(&[]);
}
@@ -188,17 +188,17 @@ impl CurrentPlugin {
}
pub fn host_context<T: Clone + 'static>(&mut self) -> Result<T, Error> {
let (linker, store) = self.linker_and_store();
let Some(Extern::Global(xs)) = linker.get(&mut *store, EXTISM_ENV_MODULE, "extism_context")
let (linker, mut store) = self.linker_and_store();
let Some(Extern::Global(xs)) = linker.get(&mut store, EXTISM_ENV_MODULE, "extism_context")
else {
anyhow::bail!("unable to locate an extism kernel global: extism_context",)
};
let Val::ExternRef(Some(xs)) = xs.get(&mut *store) else {
let Val::ExternRef(Some(xs)) = xs.get(&mut store) else {
anyhow::bail!("expected extism_context to be an externref value",)
};
match xs.data(&mut *store)?.downcast_ref::<T>().cloned() {
match xs.data(&mut store)?.downcast_ref::<T>().cloned() {
Some(xs) => Ok(xs.clone()),
None => anyhow::bail!("could not downcast extism_context",),
}
@@ -216,7 +216,7 @@ impl CurrentPlugin {
if let Some(f) = linker.get(&mut store, EXTISM_ENV_MODULE, "alloc") {
f.into_func()
.unwrap()
.call(&mut *store, &[Val::I64(n as i64)], output)?;
.call(&mut store, &[Val::I64(n as i64)], output)?;
} else {
anyhow::bail!("{} unable to allocate memory", self.id);
}
@@ -238,11 +238,11 @@ impl CurrentPlugin {
/// Free a block of Extism plugin memory
pub fn memory_free(&mut self, handle: MemoryHandle) -> Result<(), Error> {
let (linker, store) = self.linker_and_store();
if let Some(f) = linker.get(&mut *store, EXTISM_ENV_MODULE, "free") {
let (linker, mut store) = self.linker_and_store();
if let Some(f) = linker.get(&mut store, EXTISM_ENV_MODULE, "free") {
f.into_func()
.unwrap()
.call(&mut *store, &[Val::I64(handle.offset as i64)], &mut [])?;
.call(&mut store, &[Val::I64(handle.offset as i64)], &mut [])?;
} else {
anyhow::bail!("unable to locate an extism kernel function: free",)
}
@@ -250,12 +250,12 @@ impl CurrentPlugin {
}
pub fn memory_length(&mut self, offs: u64) -> Result<u64, Error> {
let (linker, store) = self.linker_and_store();
let (linker, mut store) = self.linker_and_store();
let output = &mut [Val::I64(0)];
if let Some(f) = linker.get(&mut *store, EXTISM_ENV_MODULE, "length") {
if let Some(f) = linker.get(&mut store, EXTISM_ENV_MODULE, "length") {
f.into_func()
.unwrap()
.call(&mut *store, &[Val::I64(offs as i64)], output)?;
.call(&mut store, &[Val::I64(offs as i64)], output)?;
} else {
anyhow::bail!("unable to locate an extism kernel function: length",)
}
@@ -270,12 +270,12 @@ impl CurrentPlugin {
}
pub fn memory_length_unsafe(&mut self, offs: u64) -> Result<u64, Error> {
let (linker, store) = self.linker_and_store();
let (linker, mut store) = self.linker_and_store();
let output = &mut [Val::I64(0)];
if let Some(f) = linker.get(&mut *store, EXTISM_ENV_MODULE, "length_unsafe") {
if let Some(f) = linker.get(&mut store, EXTISM_ENV_MODULE, "length_unsafe") {
f.into_func()
.unwrap()
.call(&mut *store, &[Val::I64(offs as i64)], output)?;
.call(&mut store, &[Val::I64(offs as i64)], output)?;
} else {
anyhow::bail!("unable to locate an extism kernel function: length_unsafe",)
}
@@ -320,20 +320,9 @@ impl CurrentPlugin {
if let Some(a) = &manifest.allowed_paths {
for (k, v) in a.iter() {
let readonly = k.starts_with("ro:");
let dir_path = if readonly { &k[3..] } else { k };
let dir = wasi_common::sync::dir::Dir::from_cap_std(
wasi_common::sync::Dir::open_ambient_dir(dir_path, auth)?,
);
let file: Box<dyn wasi_common::dir::WasiDir> = if readonly {
Box::new(readonly_dir::ReadOnlyDir::new(dir))
} else {
Box::new(dir)
};
let file = Box::new(wasi_common::sync::dir::Dir::from_cap_std(
wasi_common::sync::Dir::open_ambient_dir(k, auth)?,
));
ctx.push_preopened_dir(file, v)?;
}
}
@@ -414,12 +403,12 @@ impl CurrentPlugin {
/// Clear the current plugin error
pub fn clear_error(&mut self) {
trace!(plugin = self.id.to_string(), "CurrentPlugin::clear_error");
let (linker, store) = self.linker_and_store();
if let Some(f) = linker.get(&mut *store, EXTISM_ENV_MODULE, "error_set") {
let (linker, mut store) = self.linker_and_store();
if let Some(f) = linker.get(&mut store, EXTISM_ENV_MODULE, "error_set") {
let res = f
.into_func()
.unwrap()
.call(&mut *store, &[Val::I64(0)], &mut []);
.call(&mut store, &[Val::I64(0)], &mut []);
if let Err(e) = res {
error!(
plugin = self.id.to_string(),
@@ -451,10 +440,10 @@ impl CurrentPlugin {
let s = s.as_ref();
debug!(plugin = self.id.to_string(), "set error: {:?}", s);
let handle = self.current_plugin_mut().memory_new(s)?;
let (linker, store) = self.linker_and_store();
if let Some(f) = linker.get(&mut *store, EXTISM_ENV_MODULE, "error_set") {
let (linker, mut store) = self.linker_and_store();
if let Some(f) = linker.get(&mut store, EXTISM_ENV_MODULE, "error_set") {
f.into_func().unwrap().call(
&mut *store,
&mut store,
&[Val::I64(handle.offset() as i64)],
&mut [],
)?;
@@ -465,10 +454,10 @@ impl CurrentPlugin {
}
pub(crate) fn get_error_position(&mut self) -> (u64, u64) {
let (linker, store) = self.linker_and_store();
let (linker, mut store) = self.linker_and_store();
let output = &mut [Val::I64(0)];
if let Some(f) = linker.get(&mut *store, EXTISM_ENV_MODULE, "error_get") {
if let Err(e) = f.into_func().unwrap().call(&mut *store, &[], output) {
if let Some(f) = linker.get(&mut store, EXTISM_ENV_MODULE, "error_get") {
if let Err(e) = f.into_func().unwrap().call(&mut store, &[], output) {
error!(
plugin = self.id.to_string(),
"unable to call extism:host/env::error_get: {:?}", e

View File

@@ -279,7 +279,7 @@ impl Function {
/// For example, the following defines a host function named `add_newline` that takes a
/// string parameter and returns a string result:
/// ```rust
/// extism::host_fn!(add_newline(_user_data: (); a: String) -> String { Ok(a + "\n") });
/// extism::host_fn!(add_newline(_user_data: (), a: String) -> String { Ok(a + "\n") });
/// ```
/// A few things worth noting:
/// - The function always returns a `Result` that wraps the specified return type

View File

@@ -18,7 +18,6 @@ pub(crate) mod manifest;
pub(crate) mod pdk;
mod plugin;
mod plugin_builder;
mod readonly_dir;
mod timer;
/// Extism C API

View File

@@ -377,14 +377,3 @@ pub(crate) fn log_error(
) -> Result<(), Error> {
log(tracing::Level::ERROR, caller, input, _output)
}
/// Write to logs (trace)
/// Params: i64 (offset)
/// Returns: none
pub(crate) fn log_trace(
caller: Caller<CurrentPlugin>,
input: &[Val],
_output: &mut [Val],
) -> Result<(), Error> {
log(tracing::Level::TRACE, caller, input, _output)
}

View File

@@ -81,8 +81,6 @@ pub struct Plugin {
pub(crate) store_needs_reset: bool,
pub(crate) debug_options: DebugOptions,
pub(crate) error_msg: Option<Vec<u8>>,
}
unsafe impl Send for Plugin {}
@@ -244,7 +242,6 @@ fn relink(
log_info(I64);
log_debug(I64);
log_error(I64);
log_trace(I64);
);
let mut linked = BTreeSet::new();
@@ -364,7 +361,6 @@ impl Plugin {
store_needs_reset: false,
debug_options,
_functions: imports,
error_msg: None,
};
plugin.current_plugin_mut().store = &mut plugin.store;
@@ -612,17 +608,17 @@ impl Plugin {
// Initialize the guest runtime
pub(crate) fn initialize_guest_runtime(&mut self) -> Result<(), Error> {
let store = &mut self.store;
let mut store = &mut self.store;
if let Some(runtime) = &self.runtime {
trace!(plugin = self.id.to_string(), "Plugin::initialize_runtime");
match runtime {
GuestRuntime::Haskell { init, reactor_init } => {
if let Some(reactor_init) = reactor_init {
reactor_init.call(&mut *store, &[], &mut [])?;
reactor_init.call(&mut store, &[], &mut [])?;
}
let mut results = vec![Val::I32(0); init.ty(&*store).results().len()];
let mut results = vec![Val::I32(0); init.ty(&store).results().len()];
init.call(
&mut *store,
&mut store,
&[Val::I32(0), Val::I32(0)],
results.as_mut_slice(),
)?;
@@ -632,7 +628,7 @@ impl Plugin {
);
}
GuestRuntime::Wasi { init } => {
init.call(&mut *store, &[], &mut [])?;
init.call(&mut store, &[], &mut [])?;
debug!(plugin = self.id.to_string(), "initialied WASI runtime");
}
}
@@ -645,20 +641,20 @@ impl Plugin {
fn output_memory_position(&mut self) -> Result<(u64, u64), Error> {
let out = &mut [Val::I64(0)];
let out_len = &mut [Val::I64(0)];
let store = &mut self.store;
let mut store = &mut self.store;
if let Some(f) = self
.linker
.get(&mut *store, EXTISM_ENV_MODULE, "output_offset")
.get(&mut store, EXTISM_ENV_MODULE, "output_offset")
{
f.into_func().unwrap().call(&mut *store, &[], out)?;
f.into_func().unwrap().call(&mut store, &[], out)?;
} else {
anyhow::bail!("unable to set output")
}
if let Some(f) = self
.linker
.get(&mut *store, EXTISM_ENV_MODULE, "output_length")
.get(&mut store, EXTISM_ENV_MODULE, "output_length")
{
f.into_func().unwrap().call(&mut *store, &[], out_len)?;
f.into_func().unwrap().call(&mut store, &[], out_len)?;
} else {
anyhow::bail!("unable to set output length")
}
@@ -957,11 +953,11 @@ impl Plugin {
pub(crate) fn clear_error(&mut self) -> Result<(), Error> {
trace!(plugin = self.id.to_string(), "clearing error");
let (linker, store) = self.linker_and_store();
if let Some(f) = linker.get(&mut *store, EXTISM_ENV_MODULE, "error_set") {
let (linker, mut store) = self.linker_and_store();
if let Some(f) = linker.get(&mut store, EXTISM_ENV_MODULE, "error_set") {
f.into_func()
.unwrap()
.call(store, &[Val::I64(0)], &mut [])?;
.call(&mut store, &[Val::I64(0)], &mut [])?;
Ok(())
} else {
anyhow::bail!("Plugin::clear_error failed, extism:host/env::error_set not found")

View File

@@ -1,109 +0,0 @@
use crate::*;
use wasi_common::{Error, ErrorExt};
pub struct ReadOnlyDir<D: wasi_common::WasiDir> {
inner: std::sync::Arc<D>,
}
impl<D: wasi_common::WasiDir> ReadOnlyDir<D> {
pub fn new(inner: D) -> Self {
ReadOnlyDir {
inner: std::sync::Arc::new(inner),
}
}
}
#[wiggle::async_trait]
impl<D: wasi_common::WasiDir> wasi_common::WasiDir for ReadOnlyDir<D> {
fn as_any(&self) -> &dyn std::any::Any {
self.inner.as_any()
}
async fn open_file(
&self,
symlink_follow: bool,
path: &str,
oflags: wasi_common::file::OFlags,
read: bool,
write: bool,
fdflags: wasi_common::file::FdFlags,
) -> Result<wasi_common::dir::OpenResult, Error> {
if write {
return Err(Error::not_supported());
}
self.inner
.open_file(symlink_follow, path, oflags, read, false, fdflags)
.await
}
async fn create_dir(&self, _path: &str) -> Result<(), Error> {
Err(Error::not_supported())
}
async fn readdir(
&self,
cursor: wasi_common::dir::ReaddirCursor,
) -> Result<
Box<dyn Iterator<Item = Result<wasi_common::dir::ReaddirEntity, Error>> + Send>,
Error,
> {
self.inner.readdir(cursor).await
}
async fn symlink(&self, _old_path: &str, _new_path: &str) -> Result<(), Error> {
Err(Error::not_supported())
}
async fn remove_dir(&self, _path: &str) -> Result<(), Error> {
Err(Error::not_supported())
}
async fn unlink_file(&self, _path: &str) -> Result<(), Error> {
Err(Error::not_supported())
}
async fn read_link(&self, path: &str) -> Result<std::path::PathBuf, Error> {
self.inner.read_link(path).await
}
async fn get_filestat(&self) -> Result<wasi_common::file::Filestat, Error> {
self.inner.get_filestat().await
}
async fn get_path_filestat(
&self,
path: &str,
follow_symlinks: bool,
) -> Result<wasi_common::file::Filestat, Error> {
self.inner.get_path_filestat(path, follow_symlinks).await
}
async fn rename(
&self,
_path: &str,
_dest_dir: &dyn wasi_common::WasiDir,
_dest_path: &str,
) -> Result<(), Error> {
Err(wasi_common::Error::not_supported())
}
async fn hard_link(
&self,
_path: &str,
_target_dir: &dyn wasi_common::WasiDir,
_target_path: &str,
) -> Result<(), Error> {
Err(wasi_common::Error::not_supported())
}
async fn set_times(
&self,
_path: &str,
_atime: std::option::Option<wasi_common::SystemTimeSpec>,
_mtime: std::option::Option<wasi_common::SystemTimeSpec>,
_follow_symlinks: bool,
) -> Result<(), Error> {
Err(wasi_common::Error::not_supported())
}
}

View File

@@ -505,8 +505,6 @@ pub unsafe extern "C" fn extism_plugin_call_with_host_context(
let lock = plugin.instance.clone();
let mut lock = lock.lock().unwrap();
plugin.error_msg = None;
// Get function name
let name = std::ffi::CStr::from_ptr(func_name);
let name = match name.to_str() {
@@ -553,19 +551,10 @@ pub unsafe extern "C" fn extism_plugin_error(plugin: *mut Plugin) -> *const c_ch
return std::ptr::null();
}
let offs = plugin.output.error_offset;
let ptr = plugin.current_plugin_mut().memory_ptr().add(offs as usize) as *const _;
let len = plugin
plugin
.current_plugin_mut()
.memory_length(offs)
.unwrap_or_default();
let mut data = std::slice::from_raw_parts(ptr, len as usize).to_vec();
data.push(0);
plugin.error_msg = Some(data);
plugin.error_msg.as_ref().unwrap().as_ptr() as *const _
.memory_ptr()
.add(plugin.output.error_offset as usize) as *const _
}
/// Get the length of a plugin's output data

View File

@@ -1 +0,0 @@
hello world!

View File

@@ -3,32 +3,36 @@ use quickcheck::*;
const KERNEL: &[u8] = include_bytes!("../extism-runtime.wasm");
fn extism_alloc<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, n: u64) -> u64 {
fn extism_alloc<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance, n: u64) -> u64 {
let out_alloc = &mut [Val::I64(0)];
instance
.get_func(&mut *store, "alloc")
.get_func(&mut store, "alloc")
.unwrap()
.call(store, &[Val::I64(n as i64)], out_alloc)
.call(&mut store, &[Val::I64(n as i64)], out_alloc)
.unwrap();
out_alloc[0].unwrap_i64() as u64
}
fn extism_length<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) -> u64 {
fn extism_length<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) -> u64 {
let out = &mut [Val::I64(0)];
instance
.get_func(&mut *store, "length")
.get_func(&mut store, "length")
.unwrap()
.call(store, &[Val::I64(p as i64)], out)
.call(&mut store, &[Val::I64(p as i64)], out)
.unwrap();
out[0].unwrap_i64() as u64
}
fn extism_length_unsafe<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) -> u64 {
fn extism_length_unsafe<T>(
mut store: &mut wasmtime::Store<T>,
instance: &mut Instance,
p: u64,
) -> u64 {
let out = &mut [Val::I64(0)];
instance
.get_func(&mut *store, "length_unsafe")
.get_func(&mut store, "length_unsafe")
.unwrap()
.call(store, &[Val::I64(p as i64)], out)
.call(&mut store, &[Val::I64(p as i64)], out)
.unwrap();
out[0].unwrap_i64() as u64
}
@@ -43,96 +47,122 @@ fn extism_load_u8<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance
out[0].unwrap_i32() as u8
}
fn extism_load_u64<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) -> u64 {
fn extism_load_u64<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) -> u64 {
let out = &mut [Val::I32(0)];
instance
.get_func(&mut *store, "load_u64")
.get_func(&mut store, "load_u64")
.unwrap()
.call(store, &[Val::I64(p as i64)], out)
.call(&mut store, &[Val::I64(p as i64)], out)
.unwrap();
out[0].unwrap_i64() as u64
}
fn extism_input_load_u8<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) -> u8 {
fn extism_input_load_u8<T>(
mut store: &mut wasmtime::Store<T>,
instance: &mut Instance,
p: u64,
) -> u8 {
let out = &mut [Val::I32(0)];
instance
.get_func(&mut *store, "input_load_u8")
.get_func(&mut store, "input_load_u8")
.unwrap()
.call(store, &[Val::I64(p as i64)], out)
.call(&mut store, &[Val::I64(p as i64)], out)
.unwrap();
out[0].unwrap_i32() as u8
}
fn extism_input_load_u64<T>(
store: &mut wasmtime::Store<T>,
mut store: &mut wasmtime::Store<T>,
instance: &mut Instance,
p: u64,
) -> u64 {
let out = &mut [Val::I32(0)];
instance
.get_func(&mut *store, "input_load_u64")
.get_func(&mut store, "input_load_u64")
.unwrap()
.call(store, &[Val::I64(p as i64)], out)
.call(&mut store, &[Val::I64(p as i64)], out)
.unwrap();
out[0].unwrap_i64() as u64
}
fn extism_store_u8<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64, x: u8) {
fn extism_store_u8<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64, x: u8) {
instance
.get_func(&mut *store, "store_u8")
.get_func(&mut store, "store_u8")
.unwrap()
.call(store, &[Val::I64(p as i64), Val::I32(x as i32)], &mut [])
.call(
&mut store,
&[Val::I64(p as i64), Val::I32(x as i32)],
&mut [],
)
.unwrap();
}
fn extism_store_u64<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64, x: u64) {
fn extism_store_u64<T>(
mut store: &mut wasmtime::Store<T>,
instance: &mut Instance,
p: u64,
x: u64,
) {
instance
.get_func(&mut *store, "store_u64")
.get_func(&mut store, "store_u64")
.unwrap()
.call(store, &[Val::I64(p as i64), Val::I64(x as i64)], &mut [])
.call(
&mut store,
&[Val::I64(p as i64), Val::I64(x as i64)],
&mut [],
)
.unwrap();
}
fn extism_free<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) {
fn extism_free<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) {
instance
.get_func(&mut *store, "free")
.get_func(&mut store, "free")
.unwrap()
.call(store, &[Val::I64(p as i64)], &mut [])
.call(&mut store, &[Val::I64(p as i64)], &mut [])
.unwrap();
}
fn extism_error_set<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) {
fn extism_error_set<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64) {
instance
.get_func(&mut *store, "error_set")
.get_func(&mut store, "error_set")
.unwrap()
.call(store, &[Val::I64(p as i64)], &mut [])
.call(&mut store, &[Val::I64(p as i64)], &mut [])
.unwrap();
}
fn extism_error_get<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance) -> u64 {
fn extism_error_get<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance) -> u64 {
let out = &mut [Val::I64(0)];
instance
.get_func(&mut *store, "error_get")
.get_func(&mut store, "error_get")
.unwrap()
.call(store, &[], out)
.call(&mut store, &[], out)
.unwrap();
out[0].unwrap_i64() as u64
}
fn extism_reset<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance) {
fn extism_reset<T>(mut store: &mut wasmtime::Store<T>, instance: &mut Instance) {
instance
.get_func(&mut *store, "reset")
.get_func(&mut store, "reset")
.unwrap()
.call(store, &[], &mut [])
.call(&mut store, &[], &mut [])
.unwrap();
}
fn extism_input_set<T>(store: &mut wasmtime::Store<T>, instance: &mut Instance, p: u64, l: u64) {
fn extism_input_set<T>(
mut store: &mut wasmtime::Store<T>,
instance: &mut Instance,
p: u64,
l: u64,
) {
instance
.get_func(&mut *store, "input_set")
.get_func(&mut store, "input_set")
.unwrap()
.call(store, &[Val::I64(p as i64), Val::I64(l as i64)], &mut [])
.call(
&mut store,
&[Val::I64(p as i64), Val::I64(l as i64)],
&mut [],
)
.unwrap();
}

View File

@@ -9,7 +9,6 @@ const WASM_LOOP: &[u8] = include_bytes!("../../../wasm/loop.wasm");
const WASM_GLOBALS: &[u8] = include_bytes!("../../../wasm/globals.wasm");
const WASM_REFLECT: &[u8] = include_bytes!("../../../wasm/reflect.wasm");
const WASM_HTTP: &[u8] = include_bytes!("../../../wasm/http.wasm");
const WASM_FS: &[u8] = include_bytes!("../../../wasm/read_write.wasm");
host_fn!(pub hello_world (a: String) -> String { Ok(a) });
@@ -751,26 +750,3 @@ fn test_linking() {
assert_eq!(plugin.call::<&str, i64>("run", "Hello, world!").unwrap(), 1);
}
}
#[test]
fn test_readonly_dirs() {
let wasm = Wasm::data(WASM_FS);
let manifest = Manifest::new([wasm])
.with_allowed_path("ro:src/tests/data".to_string(), "/data")
.with_config_key("path", "/data/data.txt");
let mut plugin = PluginBuilder::new(manifest)
.with_wasi(true)
.build()
.unwrap();
let res = plugin.call::<&str, &str>("try_read", "").unwrap();
assert_eq!(res, "hello world!");
let line = "hello world 2";
let res2 = plugin.call::<&str, &str>("try_write", line);
assert!(
res2.is_err(),
"Expected try_write to fail, but it succeeded."
);
}

Binary file not shown.