Skip to content
This repository was archived by the owner on Oct 3, 2025. It is now read-only.

Commit f439d36

Browse files
chore: minor PR edits and clippy fixes
- Move test to crate directory - Remove types argument from HostFuncs - Update CHANGELOG.md Signed-off-by: Henry Gressmann <[email protected]>
1 parent 22d2330 commit f439d36

File tree

6 files changed

+51
-34
lines changed

6 files changed

+51
-34
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919
### Fixed
2020

2121
- Fixed archive **no_std** support which was broken in the previous release, and added more tests to ensure it stays working
22+
- Check returns in untyped host functions ([#27](https://github.com/explodingcamera/tinywasm/pull/27)) (thanks [@WhaleKit](https://github.com/WhaleKit))
2223

2324
## [0.8.0] - 2024-08-29
2425

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/tinywasm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ libm={version="0.2", default-features=false}
2323
wasm-testsuite={version="0.3.3"}
2424
indexmap="2.7"
2525
wast={workspace=true}
26+
wat={workspace=true}
2627
eyre={workspace=true}
2728
pretty_env_logger={workspace=true}
2829
criterion={workspace=true}

crates/tinywasm/src/error.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use alloc::string::{String, ToString};
2+
use alloc::vec::Vec;
23
use core::{fmt::Display, ops::ControlFlow};
34
use tinywasm_types::FuncType;
45

@@ -20,18 +21,20 @@ pub enum Error {
2021
/// An unknown error occurred
2122
Other(String),
2223

23-
/// A function did not return a value
24-
FuncDidNotReturn,
24+
/// A host function returned an invalid value
25+
InvalidHostFnReturn {
26+
/// The expected type
27+
expected: FuncType,
28+
/// The actual value
29+
actual: Vec<tinywasm_types::WasmValue>,
30+
},
2531

2632
/// An invalid label type was encountered
2733
InvalidLabelType,
2834

2935
/// The store is not the one that the module instance was instantiated in
3036
InvalidStore,
3137

32-
/// A host function did not return results expected of it's type
33-
InvalidHostFnReturn,
34-
3538
#[cfg(feature = "std")]
3639
/// An I/O error occurred
3740
Io(crate::std::io::Error),
@@ -186,9 +189,10 @@ impl Display for Error {
186189
Self::InvalidLabelType => write!(f, "invalid label type"),
187190
Self::Other(message) => write!(f, "unknown error: {message}"),
188191
Self::UnsupportedFeature(feature) => write!(f, "unsupported feature: {feature}"),
189-
Self::FuncDidNotReturn => write!(f, "function did not return"),
192+
Self::InvalidHostFnReturn { expected, actual } => {
193+
write!(f, "invalid host function return: expected={expected:?}, actual={actual:?}")
194+
}
190195
Self::InvalidStore => write!(f, "invalid store"),
191-
Self::InvalidHostFnReturn=>write!(f, "Host function returned wrong type(s)")
192196
}
193197
}
194198
}

crates/tinywasm/src/imports.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use alloc::vec::Vec;
66
use core::fmt::Debug;
77

88
use crate::func::{FromWasmValueTuple, IntoWasmValueTuple, ValTypesFromTuple};
9-
use crate::{cold, log, Error, LinkingError, MemoryRef, MemoryRefMut, Result};
9+
use crate::{log, LinkingError, MemoryRef, MemoryRefMut, Result};
1010
use tinywasm_types::*;
1111

1212
/// The internal representation of a function
@@ -42,12 +42,11 @@ impl HostFunction {
4242

4343
/// Call the function
4444
pub fn call(&self, ctx: FuncContext<'_>, args: &[WasmValue]) -> Result<Vec<WasmValue>> {
45-
(self.func)(ctx, args, &self.ty.results)
45+
(self.func)(ctx, args)
4646
}
4747
}
4848

49-
// third argument - expected return types, for validation
50-
pub(crate) type HostFuncInner = Box<dyn Fn(FuncContext<'_>, &[WasmValue], &[ValType]) -> Result<Vec<WasmValue>>>;
49+
pub(crate) type HostFuncInner = Box<dyn Fn(FuncContext<'_>, &[WasmValue]) -> Result<Vec<WasmValue>>>;
5150

5251
/// The context of a host-function call
5352
#[derive(Debug)]
@@ -140,19 +139,26 @@ impl Extern {
140139
ty: &tinywasm_types::FuncType,
141140
func: impl Fn(FuncContext<'_>, &[WasmValue]) -> Result<Vec<WasmValue>> + 'static,
142141
) -> Self {
143-
let wrapper = move |ctx: FuncContext<'_>, params: &[WasmValue], res_ty: &[ValType]| {
144-
let ret = func(ctx, params)?;
145-
let types_match = res_ty.iter().cloned().eq(ret.iter().map(WasmValue::val_type));
146-
if types_match {
147-
Ok(ret)
148-
} else {
149-
cold();
150-
let got_types = ret.iter().map(WasmValue::val_type).collect::<Box<[_]>>();
151-
log::error!("Return from host function type mismatch: expected {:?}, got {:?}", res_ty, got_types);
152-
Err(Error::InvalidHostFnReturn)
153-
}
142+
let _ty = ty.clone();
143+
let inner_func = move |ctx: FuncContext<'_>, args: &[WasmValue]| -> Result<Vec<WasmValue>> {
144+
let _ty = _ty.clone();
145+
let result = func(ctx, args)?;
146+
147+
if result.len() != _ty.results.len() {
148+
return Err(crate::Error::InvalidHostFnReturn { expected: _ty.clone(), actual: result });
149+
};
150+
151+
result.iter().zip(_ty.results.iter()).try_for_each(|(val, ty)| {
152+
if val.val_type() != *ty {
153+
return Err(crate::Error::InvalidHostFnReturn { expected: _ty.clone(), actual: result.clone() });
154+
}
155+
Ok(())
156+
})?;
157+
158+
Ok(result)
154159
};
155-
Self::Function(Function::Host(Rc::new(HostFunction { func: Box::new(wrapper), ty: ty.clone() })))
160+
161+
Self::Function(Function::Host(Rc::new(HostFunction { func: Box::new(inner_func), ty: ty.clone() })))
156162
}
157163

158164
/// Create a new typed function import
@@ -161,7 +167,7 @@ impl Extern {
161167
P: FromWasmValueTuple + ValTypesFromTuple,
162168
R: IntoWasmValueTuple + ValTypesFromTuple + Debug,
163169
{
164-
let inner_func = move |ctx: FuncContext<'_>, args: &[WasmValue], _: &[ValType]| -> Result<Vec<WasmValue>> {
170+
let inner_func = move |ctx: FuncContext<'_>, args: &[WasmValue]| -> Result<Vec<WasmValue>> {
165171
let args = P::from_wasm_value_tuple(args)?;
166172
let result = func(ctx, args)?;
167173
Ok(result.into_wasm_value_tuple().to_vec())

tests/host_func_signature_check.rs renamed to crates/tinywasm/tests/host_func_signature_check.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use eyre::Result;
2+
use std::fmt::Write;
23
use tinywasm::{
34
types::{FuncType, ValType, WasmValue},
45
Extern, FuncContext, Imports, Module, Store,
56
};
6-
use wat;
77

88
const VAL_LISTS: &[&[WasmValue]] = &[
99
&[],
@@ -13,7 +13,7 @@ const VAL_LISTS: &[&[WasmValue]] = &[
1313
&[WasmValue::I32(0), WasmValue::F64(0.0), WasmValue::I32(0)], // reorder
1414
&[WasmValue::RefExtern(0), WasmValue::F64(0.0), WasmValue::I32(0)], // all different types
1515
];
16-
//(f64, i32, i32) and (f64) can be used to "match_none"
16+
// (f64, i32, i32) and (f64) can be used to "match_none"
1717

1818
fn get_type_lists() -> impl Iterator<Item = impl Iterator<Item = ValType> + Clone> + Clone {
1919
VAL_LISTS.iter().map(|l| l.iter().map(WasmValue::val_type))
@@ -24,7 +24,7 @@ fn get_modules() -> Vec<(Module, FuncType, Vec<WasmValue>)> {
2424
for res_types in get_type_lists() {
2525
for (arg_types, arg_vals) in val_and_tys.clone() {
2626
let ty = FuncType { results: res_types.clone().collect(), params: arg_types.collect() };
27-
result.push((proxy_module(&ty), ty, arg_vals.iter().cloned().collect()));
27+
result.push((proxy_module(&ty), ty, arg_vals.to_vec()));
2828
}
2929
}
3030
result
@@ -64,9 +64,9 @@ fn test_return_invalid_type() -> Result<()> {
6464
fn test_linking_invalid_untyped_func() -> Result<()> {
6565
// try to import host functions with function types no matching those expected by modules
6666
let mod_list = get_modules();
67-
for (module, actual_func_ty,_) in &mod_list {
68-
for (_, func_ty_to_try,_) in &mod_list {
69-
let tried_fn = Extern::func(&func_ty_to_try, |_: FuncContext<'_>, _| panic!("not intended to be called"));
67+
for (module, actual_func_ty, _) in &mod_list {
68+
for (_, func_ty_to_try, _) in &mod_list {
69+
let tried_fn = Extern::func(func_ty_to_try, |_: FuncContext<'_>, _| panic!("not intended to be called"));
7070
let mut store = Store::default();
7171
let mut imports = Imports::new();
7272
imports.define("host", "hfn", tried_fn).unwrap();
@@ -107,11 +107,12 @@ fn test_linking_invalid_typed_func() -> Result<()> {
107107
for typed_fn in matching_none.clone() {
108108
let mut store = Store::default();
109109
let mut imports = Imports::new();
110-
imports.define("host", "hfn", typed_fn.clone()).unwrap();
110+
imports.define("host", "hfn", typed_fn).unwrap();
111111
let link_failure = module.clone().instantiate(&mut store, Some(imports));
112112
link_failure.expect_err("no func in matching_none list should link to any mod");
113113
}
114114
}
115+
115116
// the valid cases are well-checked in other tests
116117
Ok(())
117118
}
@@ -145,7 +146,11 @@ fn proxy_module(func_ty: &FuncType) -> Module {
145146
let results_text = join_surround(results, "result");
146147
let params_text = join_surround(params, "param");
147148

148-
let params_gets: String = params.iter().enumerate().map(|(num, _)| format!("(local.get {num})\n")).collect();
149+
// let params_gets: String = params.iter().enumerate().map(|(num, _)| format!("(local.get {num})\n")).collect();
150+
let params_gets: String = params.iter().enumerate().fold(String::new(), |mut acc, (num, _)| {
151+
let _ = writeln!(acc, "(local.get {num})", num = num);
152+
acc
153+
});
149154

150155
let result_drops = "(drop)\n".repeat(results.len()).to_string();
151156
let wasm_text = format!(
@@ -164,6 +169,5 @@ fn proxy_module(func_ty: &FuncType) -> Module {
164169
"#
165170
);
166171
let wasm = wat::parse_str(wasm_text).expect("failed to parse wat");
167-
let res = Module::parse_bytes(&wasm).expect("failed to make module");
168-
res
172+
Module::parse_bytes(&wasm).expect("failed to make module")
169173
}

0 commit comments

Comments
 (0)