Skip to main content

wasefire_interpreter/
module.rs

1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use alloc::vec::Vec;
16use core::cmp::Ordering;
17
18use crate::cursor::*;
19use crate::parser::{SkipData, SkipElem};
20use crate::side_table::*;
21use crate::syntax::*;
22use crate::toctou::*;
23use crate::*;
24
25/// Valid module.
26#[derive(Debug, Clone)]
27pub struct Module<'m> {
28    binary: &'m [u8],
29    types: Vec<FuncType<'m>>,
30    side_table: SideTableView<'m>,
31}
32
33impl<'m> Import<'m> {
34    pub fn type_(&self, module: &Module<'m>) -> ExternType<'m> {
35        self.desc.type_(module)
36    }
37}
38
39impl ImportDesc {
40    pub fn type_<'m>(&self, module: &Module<'m>) -> ExternType<'m> {
41        match *self {
42            ImportDesc::Func(x) => ExternType::Func(module.types[x as usize]),
43            ImportDesc::Table(t) => ExternType::Table(t),
44            ImportDesc::Mem(t) => ExternType::Mem(t),
45            ImportDesc::Global(t) => ExternType::Global(t),
46        }
47    }
48}
49
50impl<'m> Module<'m> {
51    /// Validates a WASM module in binary format.
52    pub fn new(binary: &'m [u8]) -> Result<Self, Error> {
53        crate::valid::verify(binary)?;
54        Ok(unsafe { Self::new_unchecked(binary) })
55    }
56
57    /// Creates a valid module from binary format.
58    ///
59    /// # Safety
60    ///
61    /// The module must be valid.
62    pub unsafe fn new_unchecked(binary: &'m [u8]) -> Self {
63        // Only keep the sections (i.e. skip the header).
64        let mut parser = unsafe { Parser::new(&binary[8 ..]) };
65        let side_table = parser.parse_side_table().into_ok();
66        let mut module = Module { binary: parser.remaining(), types: Vec::new(), side_table };
67        if let Some(mut parser) = module.section(SectionId::Type) {
68            for _ in 0 .. parser.parse_vec().into_ok() {
69                module.types.push(parser.parse_functype().into_ok());
70            }
71        }
72        module
73    }
74
75    pub(crate) fn types(&self) -> &[FuncType<'m>] {
76        &self.types
77    }
78
79    pub(crate) fn imports(&self) -> impl Iterator<Item = Import<'m>> + use<'m> {
80        let (n, mut parser) = match self.section(SectionId::Import) {
81            None => (0, Parser::default()),
82            Some(mut parser) => (parser.parse_vec().into_ok(), parser),
83        };
84        (0 .. n).map(move |_| {
85            let module = parser.parse_name().into_ok();
86            let name = parser.parse_name().into_ok();
87            let desc = parser.parse_importdesc().into_ok();
88            Import { module, name, desc }
89        })
90    }
91}
92
93pub type Parser<'m> = parser::Parser<'m, Use>;
94
95impl<'m> Module<'m> {
96    pub(crate) fn section(&self, expected_id: SectionId) -> Option<Parser<'m>> {
97        let mut parser = unsafe { Parser::new(self.binary) };
98        loop {
99            if parser.is_empty() {
100                return None;
101            }
102            let actual_id = parser.parse_section_id().into_ok();
103            let section = parser.split_section().into_ok();
104            if actual_id == SectionId::Custom {
105                continue;
106            }
107            break match actual_id.order().cmp(&expected_id.order()) {
108                Ordering::Less => continue,
109                Ordering::Equal => Some(section),
110                Ordering::Greater => None,
111            };
112        }
113    }
114
115    pub(crate) fn func_type(&self, x: FuncIdx) -> FuncType<'m> {
116        self.types
117            [self.side_table.metadata::<Use>(x as usize).into_ok().type_idx::<Use>().into_ok()]
118    }
119
120    pub(crate) fn table_type(&self, x: TableIdx) -> TableType {
121        let mut parser = self.section(SectionId::Table).unwrap();
122        for i in 0 .. parser.parse_vec().into_ok() {
123            let t = parser.parse_tabletype().into_ok();
124            if i == x as usize {
125                return t;
126            }
127        }
128        unreachable!()
129    }
130
131    pub(crate) fn mem_type(&self, x: MemIdx) -> MemType {
132        let mut parser = self.section(SectionId::Memory).unwrap();
133        for i in 0 .. parser.parse_vec().into_ok() {
134            let t = parser.parse_memtype().into_ok();
135            if i == x as usize {
136                return t;
137            }
138        }
139        unreachable!()
140    }
141
142    pub(crate) fn global_type(&self, x: GlobalIdx) -> GlobalType {
143        let mut parser = self.section(SectionId::Global).unwrap();
144        for i in 0 .. parser.parse_vec().into_ok() {
145            let t = parser.parse_globaltype().into_ok();
146            parser.skip_to_end(0).into_ok();
147            if i == x as usize {
148                return t;
149            }
150        }
151        unreachable!()
152    }
153
154    pub(crate) fn export(&self, expected_name: &str) -> Option<ExportDesc> {
155        let mut parser = self.section(SectionId::Export).unwrap();
156        for _ in 0 .. parser.parse_vec().into_ok() {
157            let actual_name = parser.parse_name().into_ok();
158            let desc = parser.parse_exportdesc().into_ok();
159            if actual_name == expected_name {
160                return Some(desc);
161            }
162        }
163        None
164    }
165
166    pub(crate) fn elem(&self, x: ElemIdx) -> Parser<'m> {
167        let mut parser = self.section(SectionId::Element).unwrap();
168        for i in 0 .. parser.parse_vec().into_ok() {
169            if i == x as usize {
170                return parser;
171            }
172            parser.parse_elem(&mut SkipElem).into_ok();
173        }
174        unreachable!()
175    }
176
177    pub(crate) fn func(&self, x: FuncIdx) -> (Parser<'m>, Cursor<'m, BranchTableEntry>) {
178        let metadata = self.side_table.metadata::<Use>(x as usize).into_ok();
179        let mut parser = unsafe { Parser::new(self.binary) };
180        unsafe { parser.restore(metadata.parser_state::<Use>().into_ok()) };
181        (parser, Cursor::new(metadata.branch_table::<Use>().into_ok()))
182    }
183
184    pub(crate) fn data(&self, x: DataIdx) -> Parser<'m> {
185        let mut parser = self.section(SectionId::Data).unwrap();
186        for i in 0 .. parser.parse_vec().into_ok() {
187            if i == x as usize {
188                return parser;
189            }
190            parser.parse_data(&mut SkipData).into_ok();
191        }
192        unreachable!()
193    }
194}