Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ed1e181

Browse files
feat: linker errors
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 0382b06 commit ed1e181

File tree

6 files changed

+161
-110
lines changed

6 files changed

+161
-110
lines changed

crates/parser/src/conversion.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result<Im
7070
module: import.module.to_string().into_boxed_str(),
7171
name: import.name.to_string().into_boxed_str(),
7272
kind: match import.ty {
73-
wasmparser::TypeRef::Func(ty) => ImportKind::Func(ty),
73+
wasmparser::TypeRef::Func(ty) => ImportKind::Function(ty),
7474
wasmparser::TypeRef::Table(ty) => ImportKind::Table(convert_module_table(ty)?),
75-
wasmparser::TypeRef::Memory(ty) => ImportKind::Mem(convert_module_memory(ty)?),
75+
wasmparser::TypeRef::Memory(ty) => ImportKind::Memory(convert_module_memory(ty)?),
7676
wasmparser::TypeRef::Global(ty) => {
7777
ImportKind::Global(GlobalType { mutable: ty.mutable, ty: convert_valtype(&ty.content_type) })
7878
}

crates/tinywasm/src/error.rs

Lines changed: 91 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,83 @@ use tinywasm_types::FuncType;
55
#[cfg(feature = "parser")]
66
use tinywasm_parser::ParseError;
77

8+
/// A tinywasm error
9+
#[derive(Debug)]
10+
pub enum Error {
11+
#[cfg(feature = "parser")]
12+
/// A parsing error occurred
13+
ParseError(ParseError),
14+
15+
#[cfg(feature = "std")]
16+
/// An I/O error occurred
17+
Io(crate::std::io::Error),
18+
19+
/// A WebAssembly feature is not supported
20+
UnsupportedFeature(String),
21+
22+
/// An unknown error occurred
23+
Other(String),
24+
25+
/// A WebAssembly trap occurred
26+
Trap(Trap),
27+
28+
/// A linking error occurred
29+
Linker(LinkingError),
30+
31+
/// A function did not return a value
32+
FuncDidNotReturn,
33+
34+
/// The stack is empty
35+
StackUnderflow,
36+
37+
/// The label stack is empty
38+
LabelStackUnderflow,
39+
40+
/// An invalid label type was encountered
41+
InvalidLabelType,
42+
43+
/// The call stack is empty
44+
CallStackEmpty,
45+
46+
/// The store is not the one that the module instance was instantiated in
47+
InvalidStore,
48+
49+
/// Missing import
50+
MissingImport {
51+
/// The module name
52+
module: String,
53+
/// The import name
54+
name: String,
55+
},
56+
57+
/// Could not resolve an import
58+
CouldNotResolveImport {
59+
/// The module name
60+
module: String,
61+
/// The import name
62+
name: String,
63+
},
64+
}
65+
66+
#[derive(Debug)]
67+
/// A linking error
68+
pub enum LinkingError {
69+
/// An unknown import was encountered
70+
UnknownImport {
71+
/// The module name
72+
module: String,
73+
/// The import name
74+
name: String,
75+
},
76+
/// A mismatched import type was encountered
77+
MismatchedImportType {
78+
/// The module name
79+
module: String,
80+
/// The import name
81+
name: String,
82+
},
83+
}
84+
885
#[derive(Debug)]
986
/// A WebAssembly trap
1087
///
@@ -84,67 +161,20 @@ impl Trap {
84161
}
85162
}
86163

87-
#[derive(Debug)]
88-
/// A tinywasm error
89-
pub enum Error {
90-
#[cfg(feature = "parser")]
91-
/// A parsing error occurred
92-
ParseError(ParseError),
93-
94-
#[cfg(feature = "std")]
95-
/// An I/O error occurred
96-
Io(crate::std::io::Error),
97-
98-
/// A WebAssembly feature is not supported
99-
UnsupportedFeature(String),
100-
101-
/// An unknown error occurred
102-
Other(String),
103-
104-
/// A WebAssembly trap occurred
105-
Trap(Trap),
106-
107-
/// A function did not return a value
108-
FuncDidNotReturn,
109-
110-
/// The stack is empty
111-
StackUnderflow,
112-
113-
/// The label stack is empty
114-
LabelStackUnderflow,
115-
116-
/// An invalid label type was encountered
117-
InvalidLabelType,
118-
119-
/// The call stack is empty
120-
CallStackEmpty,
121-
122-
/// The store is not the one that the module instance was instantiated in
123-
InvalidStore,
124-
125-
/// Missing import
126-
MissingImport {
127-
/// The module name
128-
module: String,
129-
/// The import name
130-
name: String,
131-
},
132-
133-
/// Could not resolve an import
134-
CouldNotResolveImport {
135-
/// The module name
136-
module: String,
137-
/// The import name
138-
name: String,
139-
},
164+
impl LinkingError {
165+
/// Get the message of the linking error
166+
pub fn message(&self) -> &'static str {
167+
match self {
168+
Self::UnknownImport { .. } => "unknown import",
169+
Self::MismatchedImportType { .. } => "mismatched import type",
170+
}
171+
}
172+
}
140173

141-
/// Invalid import type
142-
InvalidImportType {
143-
/// The module name
144-
module: String,
145-
/// The import name
146-
name: String,
147-
},
174+
impl From<LinkingError> for Error {
175+
fn from(value: LinkingError) -> Self {
176+
Self::Linker(value)
177+
}
148178
}
149179

150180
impl From<Trap> for Error {
@@ -163,6 +193,7 @@ impl Display for Error {
163193
Self::Io(err) => write!(f, "I/O error: {}", err),
164194

165195
Self::Trap(trap) => write!(f, "trap: {}", trap.message()),
196+
Self::Linker(err) => write!(f, "linking error: {}", err.message()),
166197
Self::CallStackEmpty => write!(f, "call stack empty"),
167198
Self::InvalidLabelType => write!(f, "invalid label type"),
168199
Self::Other(message) => write!(f, "unknown error: {}", message),
@@ -179,10 +210,6 @@ impl Display for Error {
179210
Self::CouldNotResolveImport { module, name } => {
180211
write!(f, "could not resolve import: {}.{}", module, name)
181212
}
182-
183-
Self::InvalidImportType { module, name } => {
184-
write!(f, "invalid import type: {}.{}", module, name)
185-
}
186213
}
187214
}
188215
}

crates/tinywasm/src/imports.rs

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ pub enum Extern {
9999
Memory(ExternMemory),
100100

101101
/// A function
102-
Func(Function),
102+
Function(Function),
103103
}
104104

105105
/// A function
@@ -152,7 +152,7 @@ impl Extern {
152152
func(ctx, &args)
153153
};
154154

155-
Self::Func(Function::Host(HostFunction { func: Arc::new(inner_func), ty: ty.clone() }))
155+
Self::Function(Function::Host(HostFunction { func: Arc::new(inner_func), ty: ty.clone() }))
156156
}
157157

158158
/// Create a new typed function import
@@ -171,15 +171,15 @@ impl Extern {
171171

172172
let ty = tinywasm_types::FuncType { params: P::val_types(), results: R::val_types() };
173173

174-
Self::Func(Function::Host(HostFunction { func: Arc::new(inner_func), ty }))
174+
Self::Function(Function::Host(HostFunction { func: Arc::new(inner_func), ty }))
175175
}
176176

177177
pub(crate) fn kind(&self) -> ExternalKind {
178178
match self {
179179
Self::Global(_) => ExternalKind::Global,
180180
Self::Table(_) => ExternalKind::Table,
181181
Self::Memory(_) => ExternalKind::Memory,
182-
Self::Func(_) => ExternalKind::Func,
182+
Self::Function(_) => ExternalKind::Func,
183183
}
184184
}
185185
}
@@ -273,6 +273,22 @@ impl Imports {
273273
None
274274
}
275275

276+
fn compare_types<T>(import: &Import, expected: &T, actual: &T) -> Result<()>
277+
where
278+
T: Debug + PartialEq,
279+
{
280+
if expected != actual {
281+
log::error!("failed to link import {}, expected {:?}, got {:?}", import.name, expected, actual);
282+
return Err(crate::LinkingError::MismatchedImportType {
283+
module: import.module.to_string(),
284+
name: import.name.to_string(),
285+
}
286+
.into());
287+
}
288+
289+
Ok(())
290+
}
291+
276292
pub(crate) fn link(
277293
mut self,
278294
store: &mut crate::Store,
@@ -291,46 +307,50 @@ impl Imports {
291307

292308
match val {
293309
// A link to something that needs to be added to the store
294-
ResolvedExtern::Extern(ex) => {
295-
// check if the kind matches
296-
let kind = ex.kind();
297-
if kind != (&import.kind).into() {
298-
return Err(crate::Error::InvalidImportType {
310+
ResolvedExtern::Extern(ex) => match (ex, &import.kind) {
311+
(Extern::Global(extern_global), ImportKind::Global(ty)) => {
312+
Self::compare_types(import, &extern_global.ty, ty)?;
313+
imports.globals.push(store.add_global(extern_global.ty, extern_global.val.into(), idx)?);
314+
}
315+
(Extern::Table(extern_table), ImportKind::Table(ty)) => {
316+
Self::compare_types(import, &extern_table.ty.element_type, &ty.element_type)?;
317+
// TODO: do we need to check any limits?
318+
imports.tables.push(store.add_table(extern_table.ty, idx)?);
319+
}
320+
(Extern::Memory(extern_memory), ImportKind::Memory(ty)) => {
321+
Self::compare_types(import, &extern_memory.ty.arch, &ty.arch)?;
322+
// TODO: do we need to check any limits?
323+
imports.memories.push(store.add_mem(extern_memory.ty, idx)?);
324+
}
325+
(Extern::Function(extern_func), ImportKind::Function(ty)) => {
326+
let import_func_type = module.data.func_types.get(*ty as usize).ok_or_else(|| {
327+
crate::Error::CouldNotResolveImport {
328+
module: import.module.to_string(),
329+
name: import.name.to_string(),
330+
}
331+
})?;
332+
333+
Self::compare_types(import, extern_func.ty(), import_func_type)?;
334+
imports.funcs.push(store.add_func(extern_func, *ty, idx)?);
335+
}
336+
_ => {
337+
return Err(crate::LinkingError::MismatchedImportType {
299338
module: import.module.to_string(),
300339
name: import.name.to_string(),
301-
});
302-
}
303-
304-
// TODO: check if the type matches
305-
306-
// add it to the store and get the address
307-
let addr = match ex {
308-
Extern::Global(g) => store.add_global(g.ty, g.val.into(), idx)?,
309-
Extern::Table(t) => store.add_table(t.ty, idx)?,
310-
Extern::Memory(m) => store.add_mem(m.ty, idx)?,
311-
Extern::Func(f) => {
312-
let ImportKind::Func(import_type) = import.kind else { unreachable!() };
313-
store.add_func(f, import_type, idx)?
314340
}
315-
};
316-
317-
// store the link
318-
match &kind {
319-
ExternalKind::Global => imports.globals.push(addr),
320-
ExternalKind::Table => imports.tables.push(addr),
321-
ExternalKind::Memory => imports.memories.push(addr),
322-
ExternalKind::Func => imports.funcs.push(addr),
341+
.into());
323342
}
324-
}
343+
},
325344

326345
// A link to something already in the store
327346
ResolvedExtern::Store(val) => {
328347
// check if the kind matches
329348
if val.kind() != (&import.kind).into() {
330-
return Err(crate::Error::InvalidImportType {
349+
return Err(crate::LinkingError::MismatchedImportType {
331350
module: import.module.to_string(),
332351
name: import.name.to_string(),
333-
});
352+
}
353+
.into());
334354
}
335355

336356
// TODO: check if the type matches

crates/tinywasm/src/runtime/executor/macros.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ macro_rules! mem_store {
7070
/// Doing the actual conversion from float to int is a bit tricky, because
7171
/// we need to check for overflow. This macro generates the min/max values
7272
/// for a specific conversion, which are then used in the actual conversion.
73-
/// Rust sadly doesn't have wrapping casts for floats (yet)
73+
/// Rust sadly doesn't have wrapping casts for floats yet, maybe never.
74+
/// Alternatively, https://crates.io/crates/az could be used for this but
75+
/// it's not worth the dependency.
7476
macro_rules! float_min_max {
7577
(f32, i32) => {
7678
(-2147483904.0_f32, 2147483648.0_f32)

crates/tinywasm/src/runtime/executor/mod.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
runtime::{BlockType, LabelFrame},
77
CallFrame, Error, FuncContext, LabelArgs, ModuleInstance, Result, Store, Trap,
88
};
9-
use alloc::{format, string::ToString, vec::Vec};
9+
use alloc::{string::ToString, vec::Vec};
1010
use tinywasm_types::{ElementKind, Instruction, ValType};
1111

1212
mod macros;
@@ -40,10 +40,12 @@ impl DefaultRuntime {
4040
current_module.swap(
4141
store
4242
.get_module_instance(cf.func_instance.owner)
43-
.expect(&format!(
44-
"exec expected module instance {} to exist for function",
45-
cf.func_instance.owner
46-
))
43+
.unwrap_or_else(|| {
44+
panic!(
45+
"exec expected module instance {} to exist for function",
46+
cf.func_instance.owner
47+
)
48+
})
4749
.clone(),
4850
);
4951
}

0 commit comments

Comments
 (0)