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

Commit b43bdea

Browse files
committed
fix: add returned type(s) check for functions created with Extern::func (untyped one)
1 parent 76a65cc commit b43bdea

File tree

4 files changed

+26
-9
lines changed

4 files changed

+26
-9
lines changed

crates/tinywasm/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub enum Error {
2929
/// The store is not the one that the module instance was instantiated in
3030
InvalidStore,
3131

32+
/// A host function did not return results expected of it's type
33+
InvalidHostFnReturn,
34+
3235
#[cfg(feature = "std")]
3336
/// An I/O error occurred
3437
Io(crate::std::io::Error),
@@ -185,6 +188,7 @@ impl Display for Error {
185188
Self::UnsupportedFeature(feature) => write!(f, "unsupported feature: {feature}"),
186189
Self::FuncDidNotReturn => write!(f, "function did not return"),
187190
Self::InvalidStore => write!(f, "invalid store"),
191+
Self::InvalidHostFnReturn=>write!(f, "Host function returned wrong type(s)")
188192
}
189193
}
190194
}

crates/tinywasm/src/func.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ impl FuncHandle {
5151
let func_inst = store.get_func(self.addr);
5252
let wasm_func = match &func_inst.func {
5353
Function::Host(host_func) => {
54-
let func = &host_func.clone().func;
54+
let host_func = host_func.clone();
5555
let ctx = FuncContext { store, module_addr: self.module_addr };
56-
return (func)(ctx, params);
56+
return host_func.call(ctx, params);
5757
}
5858
Function::Wasm(wasm_func) => wasm_func,
5959
};

crates/tinywasm/src/imports.rs

Lines changed: 18 additions & 5 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::{log, LinkingError, MemoryRef, MemoryRefMut, Result};
9+
use crate::{cold, log, Error, LinkingError, MemoryRef, MemoryRefMut, Result};
1010
use tinywasm_types::*;
1111

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

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

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

5152
/// The context of a host-function call
5253
#[derive(Debug)]
@@ -139,7 +140,19 @@ impl Extern {
139140
ty: &tinywasm_types::FuncType,
140141
func: impl Fn(FuncContext<'_>, &[WasmValue]) -> Result<Vec<WasmValue>> + 'static,
141142
) -> Self {
142-
Self::Function(Function::Host(Rc::new(HostFunction { func: Box::new(func), ty: ty.clone() })))
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+
}
154+
};
155+
Self::Function(Function::Host(Rc::new(HostFunction { func: Box::new(wrapper), ty: ty.clone() })))
143156
}
144157

145158
/// Create a new typed function import
@@ -148,7 +161,7 @@ impl Extern {
148161
P: FromWasmValueTuple + ValTypesFromTuple,
149162
R: IntoWasmValueTuple + ValTypesFromTuple + Debug,
150163
{
151-
let inner_func = move |ctx: FuncContext<'_>, args: &[WasmValue]| -> Result<Vec<WasmValue>> {
164+
let inner_func = move |ctx: FuncContext<'_>, args: &[WasmValue], _: &[ValType]| -> Result<Vec<WasmValue>> {
152165
let args = P::from_wasm_value_tuple(args)?;
153166
let result = func(ctx, args)?;
154167
Ok(result.into_wasm_value_tuple().to_vec())

crates/tinywasm/src/interpreter/executor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
331331
let func = &host_func.clone();
332332
let params = self.stack.values.pop_params(&host_func.ty.params);
333333
let res =
334-
(func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params).to_cf()?;
334+
func.call(FuncContext { store: self.store, module_addr: self.module.id() }, &params).to_cf()?;
335335
self.stack.values.extend_from_wasmvalues(&res);
336336
self.cf.incr_instr_ptr();
337337
return ControlFlow::Continue(());
@@ -370,7 +370,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
370370
let host_func = host_func.clone();
371371
let params = self.stack.values.pop_params(&host_func.ty.params);
372372
let res =
373-
match (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params) {
373+
match host_func.call(FuncContext { store: self.store, module_addr: self.module.id() }, &params) {
374374
Ok(res) => res,
375375
Err(e) => return ControlFlow::Break(Some(e)),
376376
};

0 commit comments

Comments
 (0)