1use alloc::{
2 collections::btree_set::{self, BTreeSet},
3 vec::Vec,
4};
5use core::iter::Map;
6
7use crate::{
8 core::{
9 decoding::{
10 modules::sections::{decode_section_if_ty_matches, SectionTy},
11 reader::{span::Span, WasmDecoder},
12 },
13 sidetable::Sidetable,
14 structure::{
15 modules::{
16 data_segments::DataSegment,
17 element_segments::ElemType,
18 exports::{Export, ExportDesc},
19 globals::Global,
20 imports::{Import, ImportDesc},
21 indices::{
22 DataIdx, ElemIdx, ExtendedIdxVec, FuncIdx, GlobalIdx, IdxVec,
23 IdxVecOverflowError, MemIdx, TableIdx, TypeIdx,
24 },
25 },
26 types::{ExternType, FuncType, GlobalType, MemType, ResultType, TableType},
27 },
28 utils::ToUsizeExt,
29 },
30 validation::{config::ValidationConfig, modules::functions::decode_and_validate_code_section},
31 CustomSection, DecodingError, ValidationError,
32};
33
34pub mod error;
35pub mod instructions;
36pub mod modules;
37pub mod types;
38pub mod validation_stack;
39
40pub mod config;
41
42#[derive(Clone, Debug)]
48pub struct Module<'bytecode> {
49 pub(crate) wasm: &'bytecode [u8],
50 pub(crate) types: IdxVec<TypeIdx, FuncType>,
51 pub(crate) imports: Vec<Import<'bytecode>>,
52 pub(crate) functions: ExtendedIdxVec<FuncIdx, TypeIdx>,
53 pub(crate) tables: ExtendedIdxVec<TableIdx, TableType>,
54 pub(crate) memories: ExtendedIdxVec<MemIdx, MemType>,
55 pub(crate) globals: ExtendedIdxVec<GlobalIdx, Global>,
56 pub(crate) exports: Vec<Export<'bytecode>>,
57 pub(crate) elements: IdxVec<ElemIdx, ElemType>,
58 pub(crate) data: IdxVec<DataIdx, DataSegment>,
59 pub(crate) func_blocks_stps: Vec<(Span, usize)>,
62 pub(crate) sidetable: Sidetable,
63 pub(crate) start: Option<FuncIdx>,
65 pub(crate) custom_sections: Vec<CustomSection<'bytecode>>,
66 }
68
69fn validate_no_duplicate_exports(validation_info: &Module) -> Result<(), ValidationError> {
70 let mut found_export_names: btree_set::BTreeSet<&str> = btree_set::BTreeSet::new();
71 for export in &validation_info.exports {
72 if found_export_names.contains(export.name) {
73 return Err(ValidationError::DuplicateExportName);
74 }
75 found_export_names.insert(export.name);
76 }
77 Ok(())
78}
79
80pub fn decode_and_validate<'wasm, T: ValidationConfig>(
81 wasm: &'wasm [u8],
82 user_data: &mut T,
83) -> Result<Module<'wasm>, ValidationError> {
84 let mut wasm = WasmDecoder::new(wasm);
85
86 let mut validation_context_refs: BTreeSet<FuncIdx> = BTreeSet::new();
96
97 trace!("Starting validation of bytecode");
98
99 trace!("Validating magic value");
100 let [0x00, 0x61, 0x73, 0x6d] = wasm.strip_bytes::<4>()? else {
101 return Err(DecodingError::InvalidMagic.into());
102 };
103
104 trace!("Validating version number");
105 let [0x01, 0x00, 0x00, 0x00] = wasm.strip_bytes::<4>()? else {
106 return Err(DecodingError::InvalidBinaryFormatVersion.into());
107 };
108 debug!("Header ok");
109
110 let mut custom_sections = Vec::new();
111 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
112
113 let types = decode_section_if_ty_matches(&mut wasm, SectionTy::Type, |wasm, _| {
114 wasm.decode_vec(FuncType::decode).map(|types| IdxVec::new(types).expect("that index space creation never fails because the length of the types vector is encoded as a 32-bit integer in the bytecode"))
115 }) ?
116 .unwrap_or_default();
117
118 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
119
120 let imports = decode_section_if_ty_matches(&mut wasm, SectionTy::Import, |wasm, _| {
121 wasm.decode_vec(|wasm| Import::decode_and_validate(wasm, &types))
122 })?
123 .unwrap_or_default();
124
125 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
126
127 let local_functions =
134 decode_section_if_ty_matches(&mut wasm, SectionTy::Function, |wasm, _| {
135 wasm.decode_vec(|wasm| TypeIdx::decode_and_validate(wasm, &types))
136 })?
137 .unwrap_or_default();
138
139 let imported_functions = imports.iter().filter_map(|import| match &import.desc {
140 ImportDesc::Func(type_idx) => Some(*type_idx),
141 _ => None,
142 });
143
144 let functions = ExtendedIdxVec::new(imported_functions.collect(), local_functions)
145 .map_err(|IdxVecOverflowError| ValidationError::TooManyFunctions)?;
146
147 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
148
149 let imported_tables = imports.iter().filter_map(|m| match m.desc {
150 ImportDesc::Table(table) => Some(table),
151 _ => None,
152 });
153 let local_tables = decode_section_if_ty_matches(&mut wasm, SectionTy::Table, |wasm, _| {
154 wasm.decode_vec(TableType::decode_and_validate)
155 })?
156 .unwrap_or_default();
157
158 let tables = ExtendedIdxVec::new(imported_tables.collect(), local_tables)
159 .map_err(|IdxVecOverflowError| ValidationError::TooManyTables)?;
160
161 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
162
163 let imported_memories = imports.iter().filter_map(|m| match m.desc {
164 ImportDesc::Mem(mem) => Some(mem),
165 _ => None,
166 });
167 let local_memories = decode_section_if_ty_matches(&mut wasm, SectionTy::Memory, |wasm, _| {
169 wasm.decode_vec(MemType::decode_and_validate)
170 })?
171 .unwrap_or_default();
172
173 let memories = ExtendedIdxVec::new(imported_memories.collect(), local_memories)
174 .map_err(|IdxVecOverflowError| ValidationError::TooManyMemories)?;
175
176 if memories.inner().len() > 1 {
177 return Err(ValidationError::UnsupportedMultipleMemoriesProposal);
178 }
179
180 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
181
182 let imported_global_types: Vec<GlobalType> = imports
183 .iter()
184 .filter_map(|m| match m.desc {
185 ImportDesc::Global(global) => Some(global),
186 _ => None,
187 })
188 .collect();
189 let local_globals = decode_section_if_ty_matches(&mut wasm, SectionTy::Global, |wasm, _| {
190 wasm.decode_vec(|wasm| {
191 Global::decode_and_validate(
192 wasm,
193 &imported_global_types,
194 &mut validation_context_refs,
195 functions.inner(),
196 )
197 })
198 })?
199 .unwrap_or_default();
200
201 let imported_globals = imported_global_types.iter().map(|ty| Global {
202 init_expr: Span::new(usize::MAX, 0),
205 ty: *ty,
206 });
207 let globals = ExtendedIdxVec::new(imported_globals.collect(), local_globals)
208 .map_err(|IdxVecOverflowError| ValidationError::TooManyGlobals)?;
209
210 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
211
212 let exports = decode_section_if_ty_matches(&mut wasm, SectionTy::Export, |wasm, _| {
213 wasm.decode_vec(|wasm| {
214 Export::decode_and_validate(
215 wasm,
216 functions.inner(),
217 tables.inner(),
218 memories.inner(),
219 globals.inner(),
220 )
221 })
222 })?
223 .unwrap_or_default();
224 validation_context_refs.extend(exports.iter().filter_map(
225 |Export { name: _, desc }| match *desc {
226 ExportDesc::Func(func_idx) => Some(func_idx),
227 _ => None,
228 },
229 ));
230
231 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
232
233 let start = decode_section_if_ty_matches(&mut wasm, SectionTy::Start, |wasm, _| {
234 let func_idx = FuncIdx::decode_and_validate(wasm, functions.inner())?;
235
236 let type_idx = unsafe { functions.inner().get(func_idx) };
241
242 let func_type = unsafe { types.get(*type_idx) };
246 if func_type
247 != &(FuncType {
248 params: ResultType {
249 valtypes: Vec::new(),
250 },
251 returns: ResultType {
252 valtypes: Vec::new(),
253 },
254 })
255 {
256 Err(ValidationError::InvalidStartFunctionSignature)
257 } else {
258 Ok(func_idx)
259 }
260 })?;
261
262 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
263
264 let elements = decode_section_if_ty_matches(&mut wasm, SectionTy::Element, |wasm, _| {
265 ElemType::decode_and_validate(
266 wasm,
267 functions.inner(),
268 &mut validation_context_refs,
269 tables.inner(),
270 &imported_global_types,
271 )
272 .map(|elements| IdxVec::new(elements).expect("that index space creation never fails because the length of the elements vector is encoded as a 32-bit integer in the bytecode"))
273 })?
274 .unwrap_or_default();
275
276 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
277
278 let data_count: Option<u32> =
283 decode_section_if_ty_matches(&mut wasm, SectionTy::DataCount, |wasm, _| {
284 wasm.decode_var_u32()
285 })?;
286
287 trace!("data count: {data_count:?}");
288
289 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
290
291 let mut sidetable = Sidetable::new();
292 let func_blocks_stps = decode_section_if_ty_matches(&mut wasm, SectionTy::Code, |wasm, _| {
293 unsafe {
299 decode_and_validate_code_section(
300 wasm,
301 &types,
302 &functions,
303 globals.inner(),
304 memories.inner(),
305 data_count,
306 tables.inner(),
307 &elements,
308 &validation_context_refs,
309 &mut sidetable,
310 user_data,
311 )
312 }
313 })?
314 .unwrap_or_default();
315
316 if func_blocks_stps.len() != functions.len_local_definitions().into_usize() {
317 return Err(ValidationError::FunctionAndCodeSectionsHaveDifferentLengths);
318 }
319
320 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
321
322 let data_section = decode_section_if_ty_matches(&mut wasm, SectionTy::Data, |wasm, _| {
323 wasm.decode_vec(|wasm| {
324 DataSegment::decode_and_validate(wasm, &imported_global_types, functions.inner(), memories.inner())
325 })
326 .map(|data_segments| IdxVec::new(data_segments).expect("that index space creation never fails because the length of the data segments vector is encoded as a 32-bit integer in the bytecode"))
327 })?
328 .unwrap_or_default();
329
330 if let Some(data_count) = data_count {
332 if data_count != data_section.len() {
333 return Err(ValidationError::DataCountAndDataSectionsLengthAreDifferent);
334 }
335 }
336
337 read_all_custom_sections(&mut wasm, &mut custom_sections)?;
338
339 if !wasm.remaining_bytes().is_empty() {
341 let remaining_section_ty = SectionTy::decode(&mut wasm).expect(
342 "that the section type is not malformed, because it must have been peeked before",
343 );
344 return Err(DecodingError::SectionOutOfOrder(remaining_section_ty).into());
345 }
346
347 debug!("Validation was successful");
348 let validation_info = Module {
349 wasm: wasm.into_inner(),
350 types,
351 imports,
352 functions,
353 tables,
354 memories,
355 globals,
356 exports,
357 func_blocks_stps,
358 sidetable,
359 data: data_section,
360 start,
361 elements,
362 custom_sections,
363 };
364 validate_no_duplicate_exports(&validation_info)?;
365
366 Ok(validation_info)
367}
368
369fn read_all_custom_sections<'wasm>(
372 wasm: &mut WasmDecoder<'wasm>,
373 custom_sections: &mut Vec<CustomSection<'wasm>>,
374) -> Result<(), ValidationError> {
375 while let Some(custom_section) =
376 decode_section_if_ty_matches(wasm, SectionTy::Custom, CustomSection::decode)?
377 {
378 custom_sections.push(custom_section);
379 }
380
381 Ok(())
382}
383
384impl<'wasm> Module<'wasm> {
385 pub fn imports<'a>(
390 &'a self,
391 ) -> Map<
392 core::slice::Iter<'a, Import<'wasm>>,
393 impl FnMut(&'a Import<'wasm>) -> (&'a str, &'a str, ExternType),
394 > {
395 self.imports.iter().map(|import| {
396 let extern_type = unsafe { import.desc.extern_type(self) };
399 (import.module_name, import.name, extern_type)
400 })
401 }
402
403 pub fn exports<'a>(
408 &'a self,
409 ) -> Map<
410 core::slice::Iter<'a, Export<'wasm>>,
411 impl FnMut(&'a Export<'wasm>) -> (&'a str, ExternType),
412 > {
413 self.exports.iter().map(|export| {
414 let extern_type = unsafe { export.desc.extern_type(self) };
417 (export.name, extern_type)
418 })
419 }
420
421 pub fn custom_sections(&self) -> &[CustomSection<'wasm>] {
425 &self.custom_sections
426 }
427}