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 | |
16 | use 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. |
29 | pub 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 | |
134 | impl<T> WasmModuleResources for &'_ T |
135 | where |
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 | |
188 | impl<T> WasmModuleResources for alloc::sync::Arc<T> |
189 | where |
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 | |