wasmparser/
resources.rs

1/* Copyright 2019 Mozilla Foundation
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 */
15
16use crate::{
17    BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType, TableType, ValType,
18    WasmFeatures,
19};
20use std::ops::Range;
21
22/// Types that qualify as Wasm function types for validation purposes.
23pub trait WasmFuncType {
24    /// Returns the number of input types.
25    fn len_inputs(&self) -> usize;
26    /// Returns the number of output types.
27    fn len_outputs(&self) -> usize;
28    /// Returns the type at given index if any.
29    ///
30    /// # Note
31    ///
32    /// The returned type may be wrapped by the user crate and thus
33    /// the actually returned type only has to be comparable to a Wasm type.
34    fn input_at(&self, at: u32) -> Option<ValType>;
35    /// Returns the type at given index if any.
36    ///
37    /// # Note
38    ///
39    /// The returned type may be wrapped by the user crate and thus
40    /// the actually returned type only has to be comparable to a Wasm type.
41    fn output_at(&self, at: u32) -> Option<ValType>;
42
43    /// Returns the list of inputs as an iterator.
44    fn inputs(&self) -> WasmFuncTypeInputs<'_, Self>
45    where
46        Self: Sized,
47    {
48        WasmFuncTypeInputs {
49            func_type: self,
50            range: 0..self.len_inputs() as u32,
51        }
52    }
53
54    /// Returns the list of outputs as an iterator.
55    fn outputs(&self) -> WasmFuncTypeOutputs<'_, Self>
56    where
57        Self: Sized,
58    {
59        WasmFuncTypeOutputs {
60            func_type: self,
61            range: 0..self.len_outputs() as u32,
62        }
63    }
64}
65
66impl<T> WasmFuncType for &'_ T
67where
68    T: ?Sized + WasmFuncType,
69{
70    fn len_inputs(&self) -> usize {
71        T::len_inputs(self)
72    }
73    fn len_outputs(&self) -> usize {
74        T::len_outputs(self)
75    }
76    fn input_at(&self, at: u32) -> Option<ValType> {
77        T::input_at(self, at)
78    }
79    fn output_at(&self, at: u32) -> Option<ValType> {
80        T::output_at(self, at)
81    }
82}
83
84/// Iterator over the inputs of a Wasm function type.
85pub struct WasmFuncTypeInputs<'a, T> {
86    /// The iterated-over function type.
87    func_type: &'a T,
88    /// The range we're iterating over.
89    range: Range<u32>,
90}
91
92impl<T> Iterator for WasmFuncTypeInputs<'_, T>
93where
94    T: WasmFuncType,
95{
96    type Item = crate::ValType;
97
98    fn next(&mut self) -> Option<Self::Item> {
99        self.range
100            .next()
101            .map(|i| self.func_type.input_at(i).unwrap())
102    }
103
104    fn size_hint(&self) -> (usize, Option<usize>) {
105        self.range.size_hint()
106    }
107}
108
109impl<T> DoubleEndedIterator for WasmFuncTypeInputs<'_, T>
110where
111    T: WasmFuncType,
112{
113    fn next_back(&mut self) -> Option<Self::Item> {
114        self.range
115            .next_back()
116            .map(|i| self.func_type.input_at(i).unwrap())
117    }
118}
119
120impl<T> ExactSizeIterator for WasmFuncTypeInputs<'_, T>
121where
122    T: WasmFuncType,
123{
124    fn len(&self) -> usize {
125        self.range.len()
126    }
127}
128
129impl<'a, T> Clone for WasmFuncTypeInputs<'a, T> {
130    fn clone(&self) -> WasmFuncTypeInputs<'a, T> {
131        WasmFuncTypeInputs {
132            func_type: self.func_type,
133            range: self.range.clone(),
134        }
135    }
136}
137
138/// Iterator over the outputs of a Wasm function type.
139pub struct WasmFuncTypeOutputs<'a, T> {
140    /// The iterated-over function type.
141    func_type: &'a T,
142    /// The range we're iterating over.
143    range: Range<u32>,
144}
145
146impl<T> Iterator for WasmFuncTypeOutputs<'_, T>
147where
148    T: WasmFuncType,
149{
150    type Item = crate::ValType;
151
152    fn next(&mut self) -> Option<Self::Item> {
153        self.range
154            .next()
155            .map(|i| self.func_type.output_at(i).unwrap())
156    }
157
158    fn size_hint(&self) -> (usize, Option<usize>) {
159        self.range.size_hint()
160    }
161}
162
163impl<T> DoubleEndedIterator for WasmFuncTypeOutputs<'_, T>
164where
165    T: WasmFuncType,
166{
167    fn next_back(&mut self) -> Option<Self::Item> {
168        self.range
169            .next_back()
170            .map(|i| self.func_type.output_at(i).unwrap())
171    }
172}
173
174impl<T> ExactSizeIterator for WasmFuncTypeOutputs<'_, T>
175where
176    T: WasmFuncType,
177{
178    fn len(&self) -> usize {
179        self.range.len()
180    }
181}
182
183impl<'a, T> Clone for WasmFuncTypeOutputs<'a, T> {
184    fn clone(&self) -> WasmFuncTypeOutputs<'a, T> {
185        WasmFuncTypeOutputs {
186            func_type: self.func_type,
187            range: self.range.clone(),
188        }
189    }
190}
191
192/// Types that qualify as Wasm validation database.
193///
194/// # Note
195///
196/// The `wasmparser` crate provides a builtin validation framework but allows
197/// users of this crate to also feed the parsed Wasm into their own data
198/// structure while parsing and also validate at the same time without
199/// the need of an additional parsing or validation step or copying data around.
200pub trait WasmModuleResources {
201    /// The function type used for validation.
202    type FuncType: WasmFuncType;
203
204    /// Returns the table at given index if any.
205    fn table_at(&self, at: u32) -> Option<TableType>;
206    /// Returns the linear memory at given index.
207    fn memory_at(&self, at: u32) -> Option<MemoryType>;
208    /// Returns the tag at given index.
209    fn tag_at(&self, at: u32) -> Option<&Self::FuncType>;
210    /// Returns the global variable at given index.
211    fn global_at(&self, at: u32) -> Option<GlobalType>;
212    /// Returns the `FuncType` associated with the given type index.
213    fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType>;
214    /// Returns the type index associated with the given function
215    /// index. type_of_function = func_type_at(type_index_of_function)
216    fn type_index_of_function(&self, func_idx: u32) -> Option<u32>;
217    /// Returns the `FuncType` associated with the given function index.
218    fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType>;
219    /// Returns the element type at the given index.
220    fn element_type_at(&self, at: u32) -> Option<RefType>;
221    /// Under the function references proposal, returns whether t1 <=
222    /// t2. Otherwise, returns whether t1 == t2
223    fn matches(&self, t1: ValType, t2: ValType) -> bool;
224    /// Check a value type. This requires using func_type_at to check references
225    fn check_value_type(
226        &self,
227        t: ValType,
228        features: &WasmFeatures,
229        offset: usize,
230    ) -> Result<(), BinaryReaderError>;
231
232    /// Checks that a `HeapType` is valid, notably its function index if one is
233    /// used.
234    fn check_heap_type(
235        &self,
236        heap_type: HeapType,
237        features: &WasmFeatures,
238        offset: usize,
239    ) -> Result<(), BinaryReaderError> {
240        // Delegate to the generic value type validation which will have the
241        // same validity checks.
242        self.check_value_type(
243            RefType {
244                nullable: true,
245                heap_type,
246            }
247            .into(),
248            features,
249            offset,
250        )
251    }
252
253    /// Returns the number of elements.
254    fn element_count(&self) -> u32;
255    /// Returns the number of bytes in the Wasm data section.
256    fn data_count(&self) -> Option<u32>;
257    /// Returns whether the function index is referenced in the module anywhere
258    /// outside of the start/function sections.
259    fn is_function_referenced(&self, idx: u32) -> bool;
260}
261
262impl<T> WasmModuleResources for &'_ T
263where
264    T: ?Sized + WasmModuleResources,
265{
266    type FuncType = T::FuncType;
267
268    fn table_at(&self, at: u32) -> Option<TableType> {
269        T::table_at(self, at)
270    }
271    fn memory_at(&self, at: u32) -> Option<MemoryType> {
272        T::memory_at(self, at)
273    }
274    fn tag_at(&self, at: u32) -> Option<&Self::FuncType> {
275        T::tag_at(self, at)
276    }
277    fn global_at(&self, at: u32) -> Option<GlobalType> {
278        T::global_at(self, at)
279    }
280    fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> {
281        T::func_type_at(self, at)
282    }
283    fn type_index_of_function(&self, func_idx: u32) -> Option<u32> {
284        T::type_index_of_function(self, func_idx)
285    }
286    fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> {
287        T::type_of_function(self, func_idx)
288    }
289    fn check_value_type(
290        &self,
291        t: ValType,
292        features: &WasmFeatures,
293        offset: usize,
294    ) -> Result<(), BinaryReaderError> {
295        T::check_value_type(self, t, features, offset)
296    }
297    fn element_type_at(&self, at: u32) -> Option<RefType> {
298        T::element_type_at(self, at)
299    }
300    fn matches(&self, t1: ValType, t2: ValType) -> bool {
301        T::matches(self, t1, t2)
302    }
303
304    fn element_count(&self) -> u32 {
305        T::element_count(self)
306    }
307    fn data_count(&self) -> Option<u32> {
308        T::data_count(self)
309    }
310    fn is_function_referenced(&self, idx: u32) -> bool {
311        T::is_function_referenced(self, idx)
312    }
313}
314
315impl<T> WasmModuleResources for std::sync::Arc<T>
316where
317    T: WasmModuleResources,
318{
319    type FuncType = T::FuncType;
320
321    fn table_at(&self, at: u32) -> Option<TableType> {
322        T::table_at(self, at)
323    }
324
325    fn memory_at(&self, at: u32) -> Option<MemoryType> {
326        T::memory_at(self, at)
327    }
328
329    fn tag_at(&self, at: u32) -> Option<&Self::FuncType> {
330        T::tag_at(self, at)
331    }
332
333    fn global_at(&self, at: u32) -> Option<GlobalType> {
334        T::global_at(self, at)
335    }
336
337    fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType> {
338        T::func_type_at(self, type_idx)
339    }
340
341    fn type_index_of_function(&self, func_idx: u32) -> Option<u32> {
342        T::type_index_of_function(self, func_idx)
343    }
344
345    fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> {
346        T::type_of_function(self, func_idx)
347    }
348
349    fn check_value_type(
350        &self,
351        t: ValType,
352        features: &WasmFeatures,
353        offset: usize,
354    ) -> Result<(), BinaryReaderError> {
355        T::check_value_type(self, t, features, offset)
356    }
357
358    fn element_type_at(&self, at: u32) -> Option<RefType> {
359        T::element_type_at(self, at)
360    }
361
362    fn matches(&self, t1: ValType, t2: ValType) -> bool {
363        T::matches(self, t1, t2)
364    }
365
366    fn element_count(&self) -> u32 {
367        T::element_count(self)
368    }
369
370    fn data_count(&self) -> Option<u32> {
371        T::data_count(self)
372    }
373
374    fn is_function_referenced(&self, idx: u32) -> bool {
375        T::is_function_referenced(self, idx)
376    }
377}
378
379impl WasmFuncType for FuncType {
380    fn len_inputs(&self) -> usize {
381        self.params().len()
382    }
383
384    fn len_outputs(&self) -> usize {
385        self.results().len()
386    }
387
388    fn input_at(&self, at: u32) -> Option<ValType> {
389        self.params().get(at as usize).copied()
390    }
391
392    fn output_at(&self, at: u32) -> Option<ValType> {
393        self.results().get(at as usize).copied()
394    }
395}