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 types::CoreTypeId, BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType,
18 SubType, TableType, ValType, WasmFeatures,
19};
20
21/// Types that qualify as Wasm validation database.
22///
23/// # Note
24///
25/// The `wasmparser` crate provides a builtin validation framework but allows
26/// users of this crate to also feed the parsed Wasm into their own data
27/// structure while parsing and also validate at the same time without
28/// the need of an additional parsing or validation step or copying data around.
29pub trait WasmModuleResources {
30 /// Returns the table at given index if any.
31 ///
32 /// The table element type must be canonicalized.
33 fn table_at(&self, at: u32) -> Option<TableType>;
34
35 /// Returns the linear memory at given index.
36 fn memory_at(&self, at: u32) -> Option<MemoryType>;
37
38 /// Returns the tag at given index.
39 ///
40 /// The tag's function type must be canonicalized.
41 fn tag_at(&self, at: u32) -> Option<&FuncType>;
42
43 /// Returns the global variable at given index.
44 ///
45 /// The global's value type must be canonicalized.
46 fn global_at(&self, at: u32) -> Option<GlobalType>;
47
48 /// Returns the `SubType` associated with the given type index.
49 ///
50 /// The sub type must be canonicalized.
51 fn sub_type_at(&self, type_index: u32) -> Option<&SubType>;
52
53 /// Returns the `SubType` associated with the given core type id.
54 fn sub_type_at_id(&self, id: CoreTypeId) -> &SubType;
55
56 /// Returns the type ID associated with the given function index.
57 fn type_id_of_function(&self, func_idx: u32) -> Option<CoreTypeId>;
58
59 /// Returns the type index associated with the given function index.
60 fn type_index_of_function(&self, func_index: u32) -> Option<u32>;
61
62 /// Returns the element type at the given index.
63 ///
64 /// The `RefType` must be canonicalized.
65 fn element_type_at(&self, at: u32) -> Option<RefType>;
66
67 /// Is `a` a subtype of `b`?
68 fn is_subtype(&self, a: ValType, b: ValType) -> bool;
69
70 /// Is the given reference type `shared`?
71 ///
72 /// While abstract heap types do carry along a `shared` flag, concrete heap
73 /// types do not. This function resolves those concrete heap types to
74 /// determine `shared`-ness.
75 fn is_shared(&self, ty: RefType) -> bool;
76
77 /// Check and canonicalize a value type.
78 ///
79 /// This will validate that `t` is valid under the `features` provided and
80 /// then additionally validate the structure of `t`. For example any type
81 /// references that `t` makes are validated and canonicalized.
82 fn check_value_type(
83 &self,
84 t: &mut ValType,
85 features: &WasmFeatures,
86 offset: usize,
87 ) -> Result<(), BinaryReaderError> {
88 features
89 .check_value_type(*t)
90 .map_err(|s| BinaryReaderError::new(s, offset))?;
91 match t {
92 ValType::Ref(r) => self.check_ref_type(r, offset),
93 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => Ok(()),
94 }
95 }
96
97 /// Check and canonicalize a reference type.
98 fn check_ref_type(
99 &self,
100 ref_type: &mut RefType,
101 offset: usize,
102 ) -> Result<(), BinaryReaderError> {
103 let is_nullable = ref_type.is_nullable();
104 let mut heap_ty = ref_type.heap_type();
105 self.check_heap_type(&mut heap_ty, offset)?;
106 *ref_type = RefType::new(is_nullable, heap_ty).unwrap();
107 Ok(())
108 }
109
110 /// Checks that a `HeapType` is valid and then additionally place it in its
111 /// canonical form.
112 ///
113 /// Similar to `check_value_type` but for heap types.
114 fn check_heap_type(
115 &self,
116 heap_type: &mut HeapType,
117 offset: usize,
118 ) -> Result<(), BinaryReaderError>;
119
120 /// Get the top type for the given heap type.
121 fn top_type(&self, heap_type: &HeapType) -> HeapType;
122
123 /// Returns the number of elements.
124 fn element_count(&self) -> u32;
125
126 /// Returns the number of bytes in the Wasm data section.
127 fn data_count(&self) -> Option<u32>;
128
129 /// Returns whether the function index is referenced in the module anywhere
130 /// outside of the start/function sections.
131 fn is_function_referenced(&self, idx: u32) -> bool;
132}
133
134impl<T> WasmModuleResources for &'_ T
135where
136 T: ?Sized + WasmModuleResources,
137{
138 fn table_at(&self, at: u32) -> Option<TableType> {
139 T::table_at(self, at)
140 }
141 fn memory_at(&self, at: u32) -> Option<MemoryType> {
142 T::memory_at(self, at)
143 }
144 fn tag_at(&self, at: u32) -> Option<&FuncType> {
145 T::tag_at(self, at)
146 }
147 fn global_at(&self, at: u32) -> Option<GlobalType> {
148 T::global_at(self, at)
149 }
150 fn sub_type_at(&self, at: u32) -> Option<&SubType> {
151 T::sub_type_at(self, at)
152 }
153 fn sub_type_at_id(&self, at: CoreTypeId) -> &SubType {
154 T::sub_type_at_id(self, at)
155 }
156 fn type_id_of_function(&self, func_idx: u32) -> Option<CoreTypeId> {
157 T::type_id_of_function(self, func_idx)
158 }
159 fn type_index_of_function(&self, func_idx: u32) -> Option<u32> {
160 T::type_index_of_function(self, func_idx)
161 }
162 fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<(), BinaryReaderError> {
163 T::check_heap_type(self, t, offset)
164 }
165 fn top_type(&self, heap_type: &HeapType) -> HeapType {
166 T::top_type(self, heap_type)
167 }
168 fn element_type_at(&self, at: u32) -> Option<RefType> {
169 T::element_type_at(self, at)
170 }
171 fn is_subtype(&self, a: ValType, b: ValType) -> bool {
172 T::is_subtype(self, a, b)
173 }
174 fn is_shared(&self, ty: RefType) -> bool {
175 T::is_shared(self, ty)
176 }
177 fn element_count(&self) -> u32 {
178 T::element_count(self)
179 }
180 fn data_count(&self) -> Option<u32> {
181 T::data_count(self)
182 }
183 fn is_function_referenced(&self, idx: u32) -> bool {
184 T::is_function_referenced(self, idx)
185 }
186}
187
188impl<T> WasmModuleResources for alloc::sync::Arc<T>
189where
190 T: WasmModuleResources,
191{
192 fn table_at(&self, at: u32) -> Option<TableType> {
193 T::table_at(self, at)
194 }
195
196 fn memory_at(&self, at: u32) -> Option<MemoryType> {
197 T::memory_at(self, at)
198 }
199
200 fn tag_at(&self, at: u32) -> Option<&FuncType> {
201 T::tag_at(self, at)
202 }
203
204 fn global_at(&self, at: u32) -> Option<GlobalType> {
205 T::global_at(self, at)
206 }
207
208 fn sub_type_at(&self, type_idx: u32) -> Option<&SubType> {
209 T::sub_type_at(self, type_idx)
210 }
211
212 fn sub_type_at_id(&self, id: CoreTypeId) -> &SubType {
213 T::sub_type_at_id(self, id)
214 }
215
216 fn type_id_of_function(&self, func_idx: u32) -> Option<CoreTypeId> {
217 T::type_id_of_function(self, func_idx)
218 }
219
220 fn type_index_of_function(&self, func_idx: u32) -> Option<u32> {
221 T::type_index_of_function(self, func_idx)
222 }
223
224 fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<(), BinaryReaderError> {
225 T::check_heap_type(self, t, offset)
226 }
227
228 fn top_type(&self, heap_type: &HeapType) -> HeapType {
229 T::top_type(self, heap_type)
230 }
231
232 fn element_type_at(&self, at: u32) -> Option<RefType> {
233 T::element_type_at(self, at)
234 }
235
236 fn is_subtype(&self, a: ValType, b: ValType) -> bool {
237 T::is_subtype(self, a, b)
238 }
239
240 fn is_shared(&self, ty: RefType) -> bool {
241 T::is_shared(self, ty)
242 }
243
244 fn element_count(&self) -> u32 {
245 T::element_count(self)
246 }
247
248 fn data_count(&self) -> Option<u32> {
249 T::data_count(self)
250 }
251
252 fn is_function_referenced(&self, idx: u32) -> bool {
253 T::is_function_referenced(self, idx)
254 }
255}
256