1use alloc::vec::Vec;
13
14use crate::binary::codesec;
15use crate::binary::datasec;
16use crate::binary::elemsec;
17use crate::binary::exportsec;
18use crate::binary::functionsec;
19use crate::binary::globalsec;
20use crate::binary::importsec;
21use crate::binary::leb128::Cursor;
22use crate::binary::memorysec;
23use crate::binary::section::{self, RawSection, SectionId};
24use crate::binary::startsec;
25use crate::binary::tablesec;
26use crate::binary::typesec;
27use crate::error::{ByteOffset, DecodeError, DecodeErrorKind};
28use crate::types::{
29 CodeBody, DataSegment, ElementSegment, Export, FuncIdx, FuncType, Global, Import, MemType,
30 TableType, TypeIdx,
31};
32
33#[derive(Debug)]
38pub struct Module<'a> {
39 pub sections: Vec<RawSection<'a>>,
41 pub types: Vec<FuncType>,
43 pub imports: Vec<Import>,
45 pub exports: Vec<Export>,
47 pub functions: Vec<TypeIdx>,
49 pub tables: Vec<TableType>,
51 pub elements: Vec<ElementSegment<'a>>,
53 pub globals: Vec<Global<'a>>,
55 pub memories: Vec<MemType>,
57 pub data: Vec<DataSegment<'a>>,
59 pub start: Option<FuncIdx>,
61 pub data_count: Option<u32>,
63 pub codes: Vec<CodeBody<'a>>,
65}
66
67impl<'a> Module<'a> {
68 pub fn decode(bytes: &'a [u8]) -> Result<Self, DecodeError> {
73 let mut cursor = Cursor::new(bytes);
74
75 section::parse_preamble(&mut cursor)?;
76 let sections = section::parse_sections(&mut cursor)?;
77 let types = match sections.iter().find(|s| s.id == SectionId::Type) {
78 Some(section) => typesec::parse_type_section(section)?,
79 None => Vec::new(),
80 };
81 let imports = match sections.iter().find(|s| s.id == SectionId::Import) {
82 Some(section) => importsec::parse_import_section(section)?,
83 None => Vec::new(),
84 };
85 let exports = match sections.iter().find(|s| s.id == SectionId::Export) {
86 Some(section) => exportsec::parse_export_section(section)?,
87 None => Vec::new(),
88 };
89 let functions = match sections.iter().find(|s| s.id == SectionId::Function) {
90 Some(section) => functionsec::parse_function_section(section)?,
91 None => Vec::new(),
92 };
93 let tables = match sections.iter().find(|s| s.id == SectionId::Table) {
94 Some(section) => tablesec::parse_table_section(section)?,
95 None => Vec::new(),
96 };
97 let elements = match sections.iter().find(|s| s.id == SectionId::Element) {
98 Some(section) => elemsec::parse_element_section(section)?,
99 None => Vec::new(),
100 };
101 let globals = match sections.iter().find(|s| s.id == SectionId::Global) {
102 Some(section) => globalsec::parse_global_section(section)?,
103 None => Vec::new(),
104 };
105 let memories = match sections.iter().find(|s| s.id == SectionId::Memory) {
106 Some(section) => memorysec::parse_memory_section(section)?,
107 None => Vec::new(),
108 };
109 let data = match sections.iter().find(|s| s.id == SectionId::Data) {
110 Some(section) => datasec::parse_data_section(section)?,
111 None => Vec::new(),
112 };
113 let start = match sections.iter().find(|s| s.id == SectionId::Start) {
114 Some(section) => Some(startsec::parse_start_section(section)?),
115 None => None,
116 };
117 let data_count = match sections.iter().find(|s| s.id == SectionId::DataCount) {
118 Some(section) => Some(datasec::parse_data_count_section(section)?),
119 None => None,
120 };
121 let codes = match sections.iter().find(|s| s.id == SectionId::Code) {
122 Some(section) => codesec::parse_code_section(section)?,
123 None => Vec::new(),
124 };
125
126 if functions.len() != codes.len() {
127 return Err(DecodeError {
128 offset: ByteOffset(0),
129 context: crate::error::DecodeContext::CodeSection,
130 kind: DecodeErrorKind::FunctionCodeLengthMismatch {
131 functions: functions.len() as u32,
132 codes: codes.len() as u32,
133 },
134 });
135 }
136
137 Ok(Module {
138 sections,
139 types,
140 imports,
141 exports,
142 functions,
143 tables,
144 elements,
145 globals,
146 memories,
147 data,
148 start,
149 data_count,
150 codes,
151 })
152 }
153
154 pub fn section(&self, id: SectionId) -> Option<&RawSection<'a>> {
156 self.sections.iter().find(|s| s.id == id)
157 }
158
159 pub fn types(&self) -> &[FuncType] {
161 &self.types
162 }
163
164 pub fn imports(&self) -> &[Import] {
166 &self.imports
167 }
168
169 pub fn exports(&self) -> &[Export] {
171 &self.exports
172 }
173
174 pub fn functions(&self) -> &[TypeIdx] {
176 &self.functions
177 }
178
179 pub fn tables(&self) -> &[TableType] {
181 &self.tables
182 }
183
184 pub fn elements(&self) -> &[ElementSegment<'a>] {
186 &self.elements
187 }
188
189 pub fn imported_function_count(&self) -> usize {
191 self.imports
192 .iter()
193 .filter(|import| matches!(import.desc, crate::types::ImportDesc::Func(_)))
194 .count()
195 }
196
197 pub fn globals(&self) -> &[Global<'a>] {
199 &self.globals
200 }
201
202 pub fn memories(&self) -> &[MemType] {
204 &self.memories
205 }
206
207 pub fn data(&self) -> &[DataSegment<'a>] {
209 &self.data
210 }
211
212 pub fn start(&self) -> Option<FuncIdx> {
214 self.start
215 }
216
217 pub fn data_count(&self) -> Option<u32> {
219 self.data_count
220 }
221
222 pub fn codes(&self) -> &[CodeBody<'a>] {
224 &self.codes
225 }
226
227 pub fn custom_sections(&self) -> impl Iterator<Item = &RawSection<'a>> {
229 self.sections.iter().filter(|s| s.id == SectionId::Custom)
230 }
231
232 pub fn section_summary(&self) -> Vec<(SectionId, usize, usize)> {
234 self.sections
235 .iter()
236 .map(|s| (s.id, s.offset, s.data.len()))
237 .collect()
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use alloc::vec;
244
245 use super::*;
246
247 #[test]
248 fn decode_minimal_module() {
249 let bytes = [
250 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, ];
253 let module = Module::decode(&bytes).unwrap();
254 assert!(module.sections.is_empty());
255 assert!(module.types.is_empty());
256 assert!(module.imports.is_empty());
257 assert!(module.exports.is_empty());
258 assert!(module.functions.is_empty());
259 assert!(module.tables.is_empty());
260 assert!(module.elements.is_empty());
261 assert!(module.globals.is_empty());
262 assert!(module.memories.is_empty());
263 assert!(module.data.is_empty());
264 assert!(module.start.is_none());
265 assert!(module.data_count.is_none());
266 assert!(module.codes.is_empty());
267 }
268
269 #[test]
270 fn decode_module_with_sections() {
271 let bytes = [
272 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B, ];
278 let module = Module::decode(&bytes).unwrap();
279 assert_eq!(module.sections.len(), 3);
280 assert_eq!(module.sections[0].id, SectionId::Type);
281 assert_eq!(module.sections[1].id, SectionId::Function);
282 assert_eq!(module.sections[2].id, SectionId::Code);
283 assert_eq!(module.types.len(), 1);
284 assert!(module.types[0].params.is_empty());
285 assert!(module.types[0].results.is_empty());
286 assert!(module.exports.is_empty());
287 assert_eq!(module.functions, vec![TypeIdx(0)]);
288 assert!(module.tables.is_empty());
289 assert!(module.elements.is_empty());
290 assert!(module.globals.is_empty());
291 assert!(module.memories.is_empty());
292 assert!(module.data.is_empty());
293 assert!(module.start.is_none());
294 assert!(module.data_count.is_none());
295 assert_eq!(module.codes.len(), 1);
296 assert!(module.codes[0].locals.is_empty());
297 assert_eq!(module.codes[0].body, &[0x0B]);
298 }
299
300 #[test]
301 fn section_lookup() {
302 let bytes = [
303 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, ];
307 let module = Module::decode(&bytes).unwrap();
308 assert!(module.section(SectionId::Type).is_some());
309 assert!(module.section(SectionId::Import).is_none());
310 assert_eq!(module.types().len(), 0);
311 assert!(module.imports().is_empty());
312 assert!(module.exports().is_empty());
313 assert!(module.functions().is_empty());
314 assert!(module.tables().is_empty());
315 assert!(module.elements().is_empty());
316 assert!(module.globals().is_empty());
317 assert!(module.memories().is_empty());
318 assert!(module.data().is_empty());
319 assert!(module.start().is_none());
320 assert!(module.data_count().is_none());
321 assert!(module.codes().is_empty());
322 }
323
324 #[test]
325 fn reject_truncated_binary() {
326 let bytes = [0x00, 0x61]; let err = Module::decode(&bytes).unwrap_err();
328 assert!(matches!(
329 err.kind,
330 crate::error::DecodeErrorKind::UnexpectedEof
331 ));
332 }
333
334 #[test]
335 fn reject_bad_magic() {
336 let bytes = [
337 0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x00, 0x00, 0x00, ];
340 let err = Module::decode(&bytes).unwrap_err();
341 assert!(matches!(
342 err.kind,
343 crate::error::DecodeErrorKind::InvalidMagic
344 ));
345 }
346
347 #[test]
348 fn reject_gc_rec_type_group_boundary() {
349 let bytes =
350 include_bytes!("../../../baedeker-testdata/spec/invalid-decode/gc-rec-type-group.wasm");
351 let err = Module::decode(bytes).unwrap_err();
352 assert_eq!(err.offset, ByteOffset(11));
353 assert_eq!(err.context, crate::error::DecodeContext::TypeSection);
354 assert!(matches!(
355 err.kind,
356 DecodeErrorKind::UnexpectedByte {
357 expected: 0x60,
358 found: 0x4E,
359 }
360 ));
361 }
362
363 #[test]
364 fn reject_gc_sub_type_definition_boundary() {
365 let bytes = include_bytes!(
366 "../../../baedeker-testdata/spec/invalid-decode/gc-sub-type-definition.wasm",
367 );
368 let err = Module::decode(bytes).unwrap_err();
369 assert_eq!(err.offset, ByteOffset(11));
370 assert_eq!(err.context, crate::error::DecodeContext::TypeSection);
371 assert!(matches!(
372 err.kind,
373 DecodeErrorKind::UnexpectedByte {
374 expected: 0x60,
375 found: 0x50,
376 }
377 ));
378 }
379
380 #[test]
381 fn reject_gc_struct_type_definition_boundary() {
382 let bytes = include_bytes!(
383 "../../../baedeker-testdata/spec/invalid-decode/gc-struct-type-definition.wasm",
384 );
385 let err = Module::decode(bytes).unwrap_err();
386 assert_eq!(err.offset, ByteOffset(11));
387 assert_eq!(err.context, crate::error::DecodeContext::TypeSection);
388 assert!(matches!(
389 err.kind,
390 DecodeErrorKind::UnexpectedByte {
391 expected: 0x60,
392 found: 0x5F,
393 }
394 ));
395 }
396
397 #[test]
398 fn reject_gc_array_type_definition_boundary() {
399 let bytes = include_bytes!(
400 "../../../baedeker-testdata/spec/invalid-decode/gc-array-type-definition.wasm",
401 );
402 let err = Module::decode(bytes).unwrap_err();
403 assert_eq!(err.offset, ByteOffset(11));
404 assert_eq!(err.context, crate::error::DecodeContext::TypeSection);
405 assert!(matches!(
406 err.kind,
407 DecodeErrorKind::UnexpectedByte {
408 expected: 0x60,
409 found: 0x5E,
410 }
411 ));
412 }
413
414 #[test]
415 fn decode_empty_fixture() {
416 let bytes = baedeker_testdata::fixture_bytes("empty");
417 let module = Module::decode(&bytes).unwrap();
418 for s in &module.sections {
421 let _ = s.id.name();
423 }
424 }
425
426 #[test]
427 fn decode_add_fixture() {
428 let bytes = baedeker_testdata::fixture_bytes("add");
429 let module = Module::decode(&bytes).unwrap();
430 assert!(
431 !module.types().is_empty(),
432 "add.wasm should decode at least one function type"
433 );
434 assert!(
435 !module.functions().is_empty(),
436 "add.wasm should decode at least one function declaration"
437 );
438 assert!(
439 !module.codes().is_empty(),
440 "add.wasm should decode at least one function body"
441 );
442 assert_eq!(module.functions().len(), module.codes().len());
443
444 assert!(
446 module.section(SectionId::Type).is_some(),
447 "add.wasm missing type section"
448 );
449 assert!(
450 module.section(SectionId::Function).is_some(),
451 "add.wasm missing function section"
452 );
453 assert!(
454 module.section(SectionId::Code).is_some(),
455 "add.wasm missing code section"
456 );
457 assert!(
458 module.section(SectionId::Export).is_some(),
459 "add.wasm missing export section"
460 );
461 assert!(
462 !module.exports().is_empty(),
463 "add.wasm export section should decode exports"
464 );
465 }
466
467 #[test]
468 fn decode_memory_fixture() {
469 let bytes = baedeker_testdata::fixture_bytes("memory");
470 let module = Module::decode(&bytes).unwrap();
471
472 assert!(
474 module.section(SectionId::Memory).is_some()
475 || module.section(SectionId::Data).is_some(),
476 "memory.wasm missing memory/data section"
477 );
478 if module.section(SectionId::Memory).is_some() {
479 assert!(
480 !module.memories().is_empty(),
481 "memory.wasm memory section should decode memory types"
482 );
483 }
484 }
485
486 #[test]
487 fn decode_module_with_global_section() {
488 let bytes = [
489 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x06, 0x06, 0x01, 0x7F, 0x00, 0x41,
490 0x2A, 0x0B,
491 ];
492 let module = Module::decode(&bytes).unwrap();
493 assert_eq!(module.globals().len(), 1);
494 assert_eq!(module.globals()[0].init_expr, &[0x41, 0x2A, 0x0B]);
495 }
496
497 #[test]
498 fn decode_module_with_table_section() {
499 let bytes = [
500 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00, 0x02,
501 ];
502 let module = Module::decode(&bytes).unwrap();
503 assert_eq!(module.tables().len(), 1);
504 assert_eq!(module.tables()[0].elem, crate::types::RefType::FuncRef);
505 assert_eq!(module.tables()[0].limits.min, 2);
506 assert_eq!(module.tables()[0].limits.max, None);
507 }
508
509 #[test]
510 fn decode_module_with_memory_section() {
511 let bytes = [
512 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x02,
513 ];
514 let module = Module::decode(&bytes).unwrap();
515 assert_eq!(module.memories().len(), 1);
516 assert_eq!(module.memories()[0].limits.min, 2);
517 assert_eq!(module.memories()[0].limits.max, None);
518 }
519
520 #[test]
521 fn decode_module_with_data_section() {
522 let bytes = [
523 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0B,
524 0x08, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x02, 0xAA, 0xBB, 0x0C, 0x01, 0x01,
525 ];
526 let module = Module::decode(&bytes).unwrap();
527 assert_eq!(module.data().len(), 1);
528 assert_eq!(module.data()[0].init, &[0xAA, 0xBB]);
529 assert_eq!(module.data_count(), Some(1));
530 }
531
532 #[test]
533 fn decode_module_with_export_section() {
534 let bytes = [
535 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x07, 0x07, 0x01, 0x03, b'a', b'd',
536 b'd', 0x00, 0x00,
537 ];
538 let module = Module::decode(&bytes).unwrap();
539 assert_eq!(module.exports().len(), 1);
540 assert_eq!(module.exports()[0].name, "add");
541 assert_eq!(
542 module.exports()[0].desc,
543 crate::types::ExportDesc::Func(crate::types::FuncIdx(0))
544 );
545 }
546
547 #[test]
548 fn decode_module_with_start_section() {
549 let bytes = [
550 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x08, 0x01, 0x02,
551 ];
552 let module = Module::decode(&bytes).unwrap();
553 assert_eq!(module.start(), Some(crate::types::FuncIdx(2)));
554 }
555
556 #[test]
557 fn decode_module_with_element_section() {
558 let bytes = [
559 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x09, 0x08, 0x01, 0x00, 0x41, 0x00,
560 0x0B, 0x02, 0x00, 0x01,
561 ];
562 let module = Module::decode(&bytes).unwrap();
563 assert_eq!(module.elements().len(), 1);
564 assert_eq!(
565 module.elements()[0].elem_type,
566 crate::types::RefType::FuncRef
567 );
568 assert!(matches!(
569 module.elements()[0].mode,
570 crate::types::ElementMode::Active {
571 table: crate::types::TableIdx(0),
572 ..
573 }
574 ));
575 }
576}