soroban_wasmi/module/
mod.rs

1mod builder;
2mod custom_section;
3mod data;
4mod element;
5mod export;
6mod global;
7mod import;
8mod init_expr;
9mod instantiate;
10mod parser;
11mod read;
12pub(crate) mod utils;
13
14use self::{
15    builder::ModuleBuilder,
16    custom_section::{CustomSections, CustomSectionsBuilder},
17    export::ExternIdx,
18    global::Global,
19    import::{ExternTypeIdx, Import},
20    parser::ModuleParser,
21};
22pub use self::{
23    custom_section::{CustomSection, CustomSectionsIter},
24    export::{ExportType, FuncIdx, MemoryIdx, ModuleExportsIter, TableIdx},
25    global::GlobalIdx,
26    import::{FuncTypeIdx, ImportName},
27    instantiate::{InstancePre, InstantiationError},
28    read::{Read, ReadError},
29};
30pub(crate) use self::{
31    data::{DataSegment, DataSegments, InitDataSegment, PassiveDataSegmentBytes},
32    element::{ElementSegment, ElementSegmentItems, ElementSegmentKind},
33    init_expr::ConstExpr,
34    utils::WasmiValueType,
35};
36use crate::{
37    collections::Map,
38    engine::{DedupFuncType, EngineFunc, EngineFuncSpan, EngineFuncSpanIter, EngineWeak},
39    Engine,
40    Error,
41    ExternType,
42    FuncType,
43    GlobalType,
44    MemoryType,
45    TableType,
46};
47use core::{iter, slice::Iter as SliceIter};
48use std::{boxed::Box, sync::Arc};
49use wasmparser::{FuncValidatorAllocations, Parser, ValidPayload, Validator};
50
51/// A parsed and validated WebAssembly module.
52#[derive(Debug, Clone)]
53pub struct Module {
54    inner: Arc<ModuleInner>,
55}
56
57/// The internal data of a [`Module`].
58#[derive(Debug)]
59struct ModuleInner {
60    engine: Engine,
61    header: ModuleHeader,
62    data_segments: DataSegments,
63    custom_sections: CustomSections,
64}
65
66/// A parsed and validated WebAssembly module header.
67#[derive(Debug, Clone)]
68pub struct ModuleHeader {
69    inner: Arc<ModuleHeaderInner>,
70}
71
72#[derive(Debug)]
73struct ModuleHeaderInner {
74    engine: EngineWeak,
75    func_types: Arc<[DedupFuncType]>,
76    imports: ModuleImports,
77    funcs: Box<[DedupFuncType]>,
78    tables: Box<[TableType]>,
79    memories: Box<[MemoryType]>,
80    globals: Box<[GlobalType]>,
81    globals_init: Box<[ConstExpr]>,
82    exports: Map<Box<str>, ExternIdx>,
83    start: Option<FuncIdx>,
84    engine_funcs: EngineFuncSpan,
85    element_segments: Box<[ElementSegment]>,
86}
87
88impl ModuleHeader {
89    /// Returns the [`Engine`] of the [`ModuleHeader`].
90    pub fn engine(&self) -> &EngineWeak {
91        &self.inner.engine
92    }
93
94    /// Returns the [`FuncType`] at the given index.
95    pub fn get_func_type(&self, func_type_idx: FuncTypeIdx) -> &DedupFuncType {
96        &self.inner.func_types[func_type_idx.into_u32() as usize]
97    }
98
99    /// Returns the [`FuncType`] of the indexed function.
100    pub fn get_type_of_func(&self, func_idx: FuncIdx) -> &DedupFuncType {
101        &self.inner.funcs[func_idx.into_u32() as usize]
102    }
103
104    /// Returns the [`GlobalType`] the the indexed global variable.
105    pub fn get_type_of_global(&self, global_idx: GlobalIdx) -> &GlobalType {
106        &self.inner.globals[global_idx.into_u32() as usize]
107    }
108
109    /// Returns the [`EngineFunc`] for the given [`FuncIdx`].
110    ///
111    /// Returns `None` if [`FuncIdx`] refers to an imported function.
112    pub fn get_engine_func(&self, func_idx: FuncIdx) -> Option<EngineFunc> {
113        let index = func_idx.into_u32();
114        let len_imported = self.inner.imports.len_funcs() as u32;
115        let index = index.checked_sub(len_imported)?;
116        // Note: It is a bug if this index access is out of bounds
117        //       therefore we panic here instead of using `get`.
118        Some(self.inner.engine_funcs.get_or_panic(index))
119    }
120
121    /// Returns the [`FuncIdx`] for the given [`EngineFunc`].
122    pub fn get_func_index(&self, func: EngineFunc) -> Option<FuncIdx> {
123        let position = self.inner.engine_funcs.position(func)?;
124        let len_imports = self.inner.imports.len_funcs as u32;
125        Some(FuncIdx::from(position + len_imports))
126    }
127
128    /// Returns the global variable type and optional initial value.
129    pub fn get_global(&self, global_idx: GlobalIdx) -> (&GlobalType, Option<&ConstExpr>) {
130        let index = global_idx.into_u32() as usize;
131        let len_imports = self.inner.imports.len_globals();
132        let global_type = self.get_type_of_global(global_idx);
133        if index < len_imports {
134            // The index refers to an imported global without init value.
135            (global_type, None)
136        } else {
137            // The index refers to an internal global with init value.
138            let init_expr = &self.inner.globals_init[index - len_imports];
139            (global_type, Some(init_expr))
140        }
141    }
142}
143
144/// The index of the default Wasm linear memory.
145pub(crate) const DEFAULT_MEMORY_INDEX: u32 = 0;
146
147/// An imported item declaration in the [`Module`].
148#[derive(Debug)]
149pub enum Imported {
150    /// The name of an imported [`Func`].
151    ///
152    /// [`Func`]: [`crate::Func`]
153    Func(ImportName),
154    /// The name of an imported [`Table`].
155    ///
156    /// [`Table`]: [`crate::Table`]
157    Table(ImportName),
158    /// The name of an imported [`Memory`].
159    ///
160    /// [`Memory`]: [`crate::Memory`]
161    Memory(ImportName),
162    /// The name of an imported [`Global`].
163    Global(ImportName),
164}
165
166/// The import names of the [`Module`] imports.
167#[derive(Debug)]
168pub struct ModuleImports {
169    /// All names and types of all imported items.
170    items: Box<[Imported]>,
171    /// The amount of imported [`Func`].
172    ///
173    /// [`Func`]: [`crate::Func`]
174    len_funcs: usize,
175    /// The amount of imported [`Global`].
176    len_globals: usize,
177    /// The amount of imported [`Memory`].
178    ///
179    /// [`Memory`]: [`crate::Memory`]
180    len_memories: usize,
181    /// The amount of imported [`Table`].
182    ///
183    /// [`Table`]: [`crate::Table`]
184    len_tables: usize,
185}
186
187impl ModuleImports {
188    /// Returns the number of imported global variables.
189    pub fn len_globals(&self) -> usize {
190        self.len_globals
191    }
192
193    /// Returns the number of imported functions.
194    pub fn len_funcs(&self) -> usize {
195        self.len_funcs
196    }
197}
198
199impl Module {
200    /// Creates a new Wasm [`Module`] from the given Wasm bytecode buffer.
201    ///
202    /// # Note
203    ///
204    /// This parses, validates and translates the buffered Wasm bytecode.
205    ///
206    /// # Errors
207    ///
208    /// - If the Wasm bytecode is malformed or fails to validate.
209    /// - If the Wasm bytecode violates restrictions
210    ///   set in the [`Config`] used by the `engine`.
211    /// - If Wasmi cannot translate the Wasm bytecode.
212    ///
213    /// [`Config`]: crate::Config
214    pub fn new(engine: &Engine, wasm: &[u8]) -> Result<Self, Error> {
215        ModuleParser::new(engine).parse_buffered(wasm)
216    }
217
218    /// Creates a new Wasm [`Module`] from the given Wasm bytecode stream.
219    ///
220    /// # Note
221    ///
222    /// This parses, validates and translates the Wasm bytecode yielded by `stream`.
223    ///
224    /// # Errors
225    ///
226    /// - If the Wasm bytecode is malformed or fails to validate.
227    /// - If the Wasm bytecode violates restrictions
228    ///   set in the [`Config`] used by the `engine`.
229    /// - If Wasmi cannot translate the Wasm bytecode.
230    ///
231    /// [`Config`]: crate::Config
232    pub fn new_streaming(engine: &Engine, stream: impl Read) -> Result<Self, Error> {
233        ModuleParser::new(engine).parse_streaming(stream)
234    }
235
236    /// Creates a new Wasm [`Module`] from the given Wasm bytecode buffer.
237    ///
238    /// # Note
239    ///
240    /// This parses and translates the buffered Wasm bytecode.
241    ///
242    /// # Safety
243    ///
244    /// - This does _not_ validate the Wasm bytecode.
245    /// - It is the caller's responsibility that the Wasm bytecode is valid.
246    /// - It is the caller's responsibility that the Wasm bytecode adheres
247    ///   to the restrictions set by the used [`Config`] of the `engine`.
248    /// - Violating the above rules is undefined behavior.
249    ///
250    /// # Errors
251    ///
252    /// - If the Wasm bytecode is malformed or contains invalid sections.
253    /// - If the Wasm bytecode fails to be compiled by Wasmi.
254    ///
255    /// [`Config`]: crate::Config
256    pub unsafe fn new_unchecked(engine: &Engine, wasm: &[u8]) -> Result<Self, Error> {
257        let parser = ModuleParser::new(engine);
258        unsafe { parser.parse_buffered_unchecked(wasm) }
259    }
260
261    /// Creates a new Wasm [`Module`] from the given byte stream.
262    ///
263    /// # Note
264    ///
265    /// This parses and translates the Wasm bytecode yielded by `stream`.
266    ///
267    /// # Safety
268    ///
269    /// - This does _not_ validate the Wasm bytecode.
270    /// - It is the caller's responsibility that the Wasm bytecode is valid.
271    /// - It is the caller's responsibility that the Wasm bytecode adheres
272    ///   to the restrictions set by the used [`Config`] of the `engine`.
273    /// - Violating the above rules is undefined behavior.
274    ///
275    /// # Errors
276    ///
277    /// - If the Wasm bytecode is malformed or contains invalid sections.
278    /// - If the Wasm bytecode fails to be compiled by Wasmi.
279    ///
280    /// [`Config`]: crate::Config
281    pub unsafe fn new_streaming_unchecked(
282        engine: &Engine,
283        stream: impl Read,
284    ) -> Result<Self, Error> {
285        let parser = ModuleParser::new(engine);
286        unsafe { parser.parse_streaming_unchecked(stream) }
287    }
288
289    /// Returns the [`Engine`] used during creation of the [`Module`].
290    pub fn engine(&self) -> &Engine {
291        &self.inner.engine
292    }
293
294    /// Returns a shared reference to the [`ModuleHeaderInner`].
295    fn module_header(&self) -> &ModuleHeaderInner {
296        &self.inner.header.inner
297    }
298
299    /// Validates `wasm` as a WebAssembly binary given the configuration (via [`Config`]) in `engine`.
300    ///
301    /// This function performs Wasm validation of the binary input WebAssembly module and
302    /// returns either `Ok`` or `Err`` depending on the results of the validation.
303    /// The [`Config`] of the `engine` is used for Wasm validation which indicates which WebAssembly
304    /// features are valid and invalid for the validation.
305    ///
306    /// # Note
307    ///
308    /// - The input `wasm` must be in binary form, the text format is not accepted by this function.
309    /// - This will only validate the `wasm` but not try to translate it. Therefore `Module::new`
310    ///   might still fail if translation of the Wasm binary input fails to translate via the Wasmi
311    ///   [`Engine`].
312    /// - Validation automatically happens as part of [`Module::new`].
313    ///
314    /// # Errors
315    ///
316    /// If Wasm validation for `wasm` fails for the given [`Config`] provided via `engine`.
317    ///
318    /// [`Config`]: crate::Config
319    pub fn validate(engine: &Engine, wasm: &[u8]) -> Result<(), Error> {
320        let mut validator = Validator::new_with_features(engine.config().wasm_features());
321        for payload in Parser::new(0).parse_all(wasm) {
322            let payload = payload?;
323            if let ValidPayload::Func(func_to_validate, func_body) = validator.payload(&payload)? {
324                func_to_validate
325                    .into_validator(FuncValidatorAllocations::default())
326                    .validate(&func_body)?;
327            }
328        }
329        Ok(())
330    }
331
332    /// Returns the number of non-imported functions of the [`Module`].
333    pub(crate) fn len_funcs(&self) -> usize {
334        self.module_header().funcs.len()
335    }
336    /// Returns the number of non-imported tables of the [`Module`].
337    pub(crate) fn len_tables(&self) -> usize {
338        self.module_header().tables.len()
339    }
340    /// Returns the number of non-imported linear memories of the [`Module`].
341    pub(crate) fn len_memories(&self) -> usize {
342        self.module_header().memories.len()
343    }
344    /// Returns the number of non-imported global variables of the [`Module`].
345    pub(crate) fn len_globals(&self) -> usize {
346        self.module_header().globals.len()
347    }
348
349    /// Returns a slice to the function types of the [`Module`].
350    ///
351    /// # Note
352    ///
353    /// The slice is stored in a `Arc` so that this operation is very cheap.
354    pub(crate) fn func_types_cloned(&self) -> Arc<[DedupFuncType]> {
355        self.module_header().func_types.clone()
356    }
357
358    /// Returns an iterator over the imports of the [`Module`].
359    pub fn imports(&self) -> ModuleImportsIter {
360        let header = self.module_header();
361        let len_imported_funcs = header.imports.len_funcs;
362        let len_imported_globals = header.imports.len_globals;
363        ModuleImportsIter {
364            engine: self.engine(),
365            names: header.imports.items.iter(),
366            funcs: header.funcs[..len_imported_funcs].iter(),
367            tables: header.tables.iter(),
368            memories: header.memories.iter(),
369            globals: header.globals[..len_imported_globals].iter(),
370        }
371    }
372
373    /// Returns an iterator over the internally defined [`Func`].
374    ///
375    /// [`Func`]: [`crate::Func`]
376    pub(crate) fn internal_funcs(&self) -> InternalFuncsIter {
377        let header = self.module_header();
378        let len_imported = header.imports.len_funcs;
379        // We skip the first `len_imported` elements in `funcs`
380        // since they refer to imported and not internally defined
381        // functions.
382        let funcs = &header.funcs[len_imported..];
383        let engine_funcs = header.engine_funcs.iter();
384        assert_eq!(funcs.len(), engine_funcs.len());
385        InternalFuncsIter {
386            iter: funcs.iter().zip(engine_funcs),
387        }
388    }
389
390    /// Returns an iterator over the [`MemoryType`] of internal linear memories.
391    fn internal_memories(&self) -> SliceIter<MemoryType> {
392        let header = self.module_header();
393        let len_imported = header.imports.len_memories;
394        // We skip the first `len_imported` elements in `memories`
395        // since they refer to imported and not internally defined
396        // linear memories.
397        let memories = &header.memories[len_imported..];
398        memories.iter()
399    }
400
401    /// Returns an iterator over the [`TableType`] of internal tables.
402    fn internal_tables(&self) -> SliceIter<TableType> {
403        let header = self.module_header();
404        let len_imported = header.imports.len_tables;
405        // We skip the first `len_imported` elements in `memories`
406        // since they refer to imported and not internally defined
407        // linear memories.
408        let tables = &header.tables[len_imported..];
409        tables.iter()
410    }
411
412    /// Returns an iterator over the internally defined [`Global`].
413    fn internal_globals(&self) -> InternalGlobalsIter {
414        let header = self.module_header();
415        let len_imported = header.imports.len_globals;
416        // We skip the first `len_imported` elements in `globals`
417        // since they refer to imported and not internally defined
418        // global variables.
419        let globals = header.globals[len_imported..].iter();
420        let global_inits = header.globals_init.iter();
421        InternalGlobalsIter {
422            iter: globals.zip(global_inits),
423        }
424    }
425
426    /// Returns an iterator over the exports of the [`Module`].
427    pub fn exports(&self) -> ModuleExportsIter {
428        ModuleExportsIter::new(self)
429    }
430
431    /// Looks up an export in this [`Module`] by its `name`.
432    ///
433    /// Returns `None` if no export with the name was found.
434    ///
435    /// # Note
436    ///
437    /// This function will return the type of an export with the given `name`.
438    pub fn get_export(&self, name: &str) -> Option<ExternType> {
439        let idx = self.module_header().exports.get(name).copied()?;
440        let ty = self.get_extern_type(idx);
441        Some(ty)
442    }
443
444    /// Returns the [`ExternType`] for a given [`ExternIdx`].
445    ///
446    /// # Note
447    ///
448    /// This function assumes that the given [`ExternType`] is valid.
449    fn get_extern_type(&self, idx: ExternIdx) -> ExternType {
450        let header = self.module_header();
451        match idx {
452            ExternIdx::Func(index) => {
453                let dedup = &header.funcs[index.into_u32() as usize];
454                let func_type = self.engine().resolve_func_type(dedup, Clone::clone);
455                ExternType::Func(func_type)
456            }
457            ExternIdx::Table(index) => {
458                let table_type = header.tables[index.into_u32() as usize];
459                ExternType::Table(table_type)
460            }
461            ExternIdx::Memory(index) => {
462                let memory_type = header.memories[index.into_u32() as usize];
463                ExternType::Memory(memory_type)
464            }
465            ExternIdx::Global(index) => {
466                let global_type = header.globals[index.into_u32() as usize];
467                ExternType::Global(global_type)
468            }
469        }
470    }
471
472    /// Returns an iterator yielding the custom sections of the Wasm [`Module`].
473    ///
474    /// # Note
475    ///
476    /// The returned iterator will yield no items if [`Config::ignore_custom_sections`]
477    /// is set to `true` even if the original Wasm module contains custom sections.
478    ///
479    ///
480    /// [`Config::ignore_custom_sections`]: crate::Config::ignore_custom_sections
481    #[inline]
482    pub fn custom_sections(&self) -> CustomSectionsIter {
483        self.inner.custom_sections.iter()
484    }
485}
486
487/// An iterator over the imports of a [`Module`].
488#[derive(Debug)]
489pub struct ModuleImportsIter<'a> {
490    engine: &'a Engine,
491    names: SliceIter<'a, Imported>,
492    funcs: SliceIter<'a, DedupFuncType>,
493    tables: SliceIter<'a, TableType>,
494    memories: SliceIter<'a, MemoryType>,
495    globals: SliceIter<'a, GlobalType>,
496}
497
498impl<'a> Iterator for ModuleImportsIter<'a> {
499    type Item = ImportType<'a>;
500
501    fn next(&mut self) -> Option<Self::Item> {
502        let import = match self.names.next() {
503            None => return None,
504            Some(imported) => match imported {
505                Imported::Func(name) => {
506                    let func_type = self.funcs.next().unwrap_or_else(|| {
507                        panic!("unexpected missing imported function for {name:?}")
508                    });
509                    let func_type = self.engine.resolve_func_type(func_type, FuncType::clone);
510                    ImportType::new(name, func_type)
511                }
512                Imported::Table(name) => {
513                    let table_type = self.tables.next().unwrap_or_else(|| {
514                        panic!("unexpected missing imported table for {name:?}")
515                    });
516                    ImportType::new(name, *table_type)
517                }
518                Imported::Memory(name) => {
519                    let memory_type = self.memories.next().unwrap_or_else(|| {
520                        panic!("unexpected missing imported linear memory for {name:?}")
521                    });
522                    ImportType::new(name, *memory_type)
523                }
524                Imported::Global(name) => {
525                    let global_type = self.globals.next().unwrap_or_else(|| {
526                        panic!("unexpected missing imported global variable for {name:?}")
527                    });
528                    ImportType::new(name, *global_type)
529                }
530            },
531        };
532        Some(import)
533    }
534
535    fn size_hint(&self) -> (usize, Option<usize>) {
536        self.names.size_hint()
537    }
538}
539
540impl<'a> ExactSizeIterator for ModuleImportsIter<'a> {
541    fn len(&self) -> usize {
542        ExactSizeIterator::len(&self.names)
543    }
544}
545
546/// A descriptor for an imported value into a Wasm [`Module`].
547///
548/// This type is primarily accessed from the [`Module::imports`] method.
549/// Each [`ImportType`] describes an import into the Wasm module with the `module/name`
550/// that it is imported from as well as the type of item that is being imported.
551#[derive(Debug)]
552pub struct ImportType<'module> {
553    /// The name of the imported item.
554    name: &'module ImportName,
555    /// The external item type.
556    ty: ExternType,
557}
558
559impl<'module> ImportType<'module> {
560    /// Creates a new [`ImportType`].
561    pub(crate) fn new<T>(name: &'module ImportName, ty: T) -> Self
562    where
563        T: Into<ExternType>,
564    {
565        Self {
566            name,
567            ty: ty.into(),
568        }
569    }
570
571    /// Returns the import name.
572    pub(crate) fn import_name(&self) -> &ImportName {
573        self.name
574    }
575
576    /// Returns the module import name.
577    pub fn module(&self) -> &'module str {
578        self.name.module()
579    }
580
581    /// Returns the field import name.
582    pub fn name(&self) -> &'module str {
583        self.name.name()
584    }
585
586    /// Returns the import item type.
587    pub fn ty(&self) -> &ExternType {
588        &self.ty
589    }
590}
591
592/// An iterator over the internally defined functions of a [`Module`].
593#[derive(Debug)]
594pub struct InternalFuncsIter<'a> {
595    iter: iter::Zip<SliceIter<'a, DedupFuncType>, EngineFuncSpanIter>,
596}
597
598impl<'a> Iterator for InternalFuncsIter<'a> {
599    type Item = (DedupFuncType, EngineFunc);
600
601    fn next(&mut self) -> Option<Self::Item> {
602        self.iter
603            .next()
604            .map(|(func_type, engine_func)| (*func_type, engine_func))
605    }
606
607    fn size_hint(&self) -> (usize, Option<usize>) {
608        self.iter.size_hint()
609    }
610}
611
612impl<'a> ExactSizeIterator for InternalFuncsIter<'a> {
613    fn len(&self) -> usize {
614        ExactSizeIterator::len(&self.iter)
615    }
616}
617
618/// An iterator over the internally defined functions of a [`Module`].
619#[derive(Debug)]
620pub struct InternalGlobalsIter<'a> {
621    iter: iter::Zip<SliceIter<'a, GlobalType>, SliceIter<'a, ConstExpr>>,
622}
623
624impl<'a> Iterator for InternalGlobalsIter<'a> {
625    type Item = (&'a GlobalType, &'a ConstExpr);
626
627    fn next(&mut self) -> Option<Self::Item> {
628        self.iter.next()
629    }
630
631    fn size_hint(&self) -> (usize, Option<usize>) {
632        self.iter.size_hint()
633    }
634}
635
636impl<'a> ExactSizeIterator for InternalGlobalsIter<'a> {
637    fn len(&self) -> usize {
638        ExactSizeIterator::len(&self.iter)
639    }
640}