wasm/validation/modules/
exports.rs

1use crate::{
2    core::{
3        decoding::reader::WasmDecoder,
4        structure::modules::{
5            exports::{Export, ExportDesc},
6            globals::Global,
7            indices::{FuncIdx, GlobalIdx, IdxVec, MemIdx, TableIdx, TypeIdx},
8        },
9    },
10    DecodingError, ExternType, MemType, Module, TableType, ValidationError,
11};
12
13impl<'wasm> Export<'wasm> {
14    pub fn decode_and_validate(
15        wasm: &mut WasmDecoder<'wasm>,
16        c_funcs: &IdxVec<FuncIdx, TypeIdx>,
17        c_tables: &IdxVec<TableIdx, TableType>,
18        c_mems: &IdxVec<MemIdx, MemType>,
19        c_globals: &IdxVec<GlobalIdx, Global>,
20    ) -> Result<Self, ValidationError> {
21        let name = wasm.decode_name()?;
22        let desc = ExportDesc::decode_and_validate(wasm, c_funcs, c_tables, c_mems, c_globals)?;
23        Ok(Export { name, desc })
24    }
25}
26
27impl ExportDesc {
28    pub fn decode_and_validate(
29        wasm: &mut WasmDecoder,
30        c_functions: &IdxVec<FuncIdx, TypeIdx>,
31        c_tables: &IdxVec<TableIdx, TableType>,
32        c_mems: &IdxVec<MemIdx, MemType>,
33        c_globals: &IdxVec<GlobalIdx, Global>,
34    ) -> Result<Self, ValidationError> {
35        let desc_id = wasm.decode_u8()?;
36
37        let desc = match desc_id {
38            0x00 => ExportDesc::Func(FuncIdx::decode_and_validate(wasm, c_functions)?),
39            0x01 => ExportDesc::Table(TableIdx::decode_and_validate(wasm, c_tables)?),
40            0x02 => ExportDesc::Mem(MemIdx::decode_and_validate(wasm, c_mems)?),
41            0x03 => ExportDesc::Global(GlobalIdx::decode_and_validate(wasm, c_globals)?),
42            other => return Err(DecodingError::MalformedExportDescDiscriminator(other).into()),
43        };
44        Ok(desc)
45    }
46
47    /// returns the external type of `self` according to typing relation,
48    /// taking `validation_info` as validation context C
49    ///
50    /// # Safety
51    ///
52    /// The caller must ensure that `self` comes from the same
53    /// [`Module`] that is passed as an argument here.
54    #[allow(unused)] // reason = "this function is analogous to ImportDesc::extern_type, however it is not yet clear if it is needed in the future"
55    pub unsafe fn extern_type(&self, validation_info: &Module) -> ExternType {
56        // TODO clean up logic for checking if an exported definition is an
57        // import
58        match self {
59            ExportDesc::Func(func_idx) => {
60                // SAFETY: The caller ensures that the current `ExportDesc`
61                // comes from the same `Module` that is passed into the
62                // current function. Therefore, the function index stored in
63                // `self` must be valid in the given `Module`.
64                let type_idx = unsafe { validation_info.functions.inner().get(*func_idx) };
65                // SAFETY: The type index was just read from the passed
66                // `Module`.  Because the `Module` struct
67                // guarantees that all indices contained in it are valid for all
68                // other `IdxVec` vectors in it, this is sound.
69                let func_type = unsafe { validation_info.types.get(*type_idx) };
70                // TODO ugly clone that should disappear when types are directly parsed from bytecode instead of vector copies
71                ExternType::Func(func_type.clone())
72            }
73            ExportDesc::Table(table_idx) => {
74                // SAFETY: The caller ensures that the current `ExportDesc`
75                // comes from the same `Module` that is passed into the
76                // current function. Therefore, the table index stored in `self`
77                // must be valid in the given `Module`.
78                let table_type = unsafe { validation_info.tables.inner().get(*table_idx) };
79
80                ExternType::Table(*table_type)
81            }
82            ExportDesc::Mem(mem_idx) => {
83                // SAFETY: The caller ensures that the current `ExportDesc`
84                // comes from the same `Module` that is passed into the
85                // current function. Therefore, the memory index stored in
86                // `self` must be valid in the given `Module`.
87                let mem_type = unsafe { validation_info.memories.inner().get(*mem_idx) };
88
89                ExternType::Mem(*mem_type)
90            }
91            ExportDesc::Global(global_idx) => {
92                // SAFETY: The caller ensures that the current `ExportDesc`
93                // comes from the same `Module` that is passed into the
94                // current function. Therefore, the global index stored in
95                // `self` must be valid in the given `Module`.
96                let global = unsafe { validation_info.globals.inner().get(*global_idx) };
97
98                ExternType::Global(global.ty)
99            }
100        }
101    }
102}