1 use crate::EventSectionReader;
2 use crate::{AliasSectionReader, InstanceSectionReader};
3 use crate::{BinaryReader, BinaryReaderError, FunctionBody, Range, Result};
4 use crate::{DataSectionReader, ElementSectionReader, ExportSectionReader};
5 use crate::{FunctionSectionReader, ImportSectionReader, TypeSectionReader};
6 use crate::{GlobalSectionReader, MemorySectionReader, TableSectionReader};
7 use std::convert::TryInto;
8 use std::fmt;
9 use std::iter;
10
11 /// An incremental parser of a binary WebAssembly module.
12 ///
13 /// This type is intended to be used to incrementally parse a WebAssembly module
14 /// as bytes become available for the module. This can also be used to parse
15 /// modules that are already entirely resident within memory.
16 ///
17 /// This primary function for a parser is the [`Parser::parse`] function which
18 /// will incrementally consume input. You can also use the [`Parser::parse_all`]
19 /// function to parse a module that is entirely resident in memory.
20 #[derive(Debug, Clone)]
21 pub struct Parser {
22 state: State,
23 offset: u64,
24 max_size: u64,
25 }
26
27 #[derive(Debug, Clone)]
28 enum State {
29 ModuleHeader,
30 SectionStart,
31 FunctionBody { remaining: u32, len: u32 },
32 Module { remaining: u32, len: u32 },
33 }
34
35 /// A successful return payload from [`Parser::parse`].
36 ///
37 /// On success one of two possible values can be returned, either that more data
38 /// is needed to continue parsing or a chunk of the input was parsed, indicating
39 /// how much of it was parsed.
40 #[derive(Debug)]
41 pub enum Chunk<'a> {
42 /// This can be returned at any time and indicates that more data is needed
43 /// to proceed with parsing. Zero bytes were consumed from the input to
44 /// [`Parser::parse`]. The `usize` value here is a hint as to how many more
45 /// bytes are needed to continue parsing.
46 NeedMoreData(u64),
47
48 /// A chunk was successfully parsed.
49 Parsed {
50 /// This many bytes of the `data` input to [`Parser::parse`] were
51 /// consumed to produce `payload`.
52 consumed: usize,
53 /// The value that we actually parsed.
54 payload: Payload<'a>,
55 },
56 }
57
58 /// Values that can be parsed from a wasm module.
59 ///
60 /// This enumeration is all possible chunks of pieces that can be parsed by a
61 /// [`Parser`] from a binary WebAssembly module. Note that for many sections the
62 /// entire section is parsed all at once, whereas other functions, like the code
63 /// section, are parsed incrementally. This is a distinction where some
64 /// sections, like the type section, are required to be fully resident in memory
65 /// (fully downloaded) before proceeding. Other sections, like the code section,
66 /// can be processed in a streaming fashion where each function is extracted
67 /// individually so it can possibly be shipped to another thread while you wait
68 /// for more functions to get downloaded.
69 ///
70 /// Note that payloads, when returned, do not indicate that the wasm module is
71 /// valid. For example when you receive a `Payload::TypeSection` the type
72 /// section itself has not yet actually been parsed. The reader returned will be
73 /// able to parse it, but you'll have to actually iterate the reader to do the
74 /// full parse. Each payload returned is intended to be a *window* into the
75 /// original `data` passed to [`Parser::parse`] which can be further processed
76 /// if necessary.
77 pub enum Payload<'a> {
78 /// Indicates the header of a WebAssembly binary.
79 ///
80 /// This header also indicates the version number that was parsed, which is
81 /// currently always 1.
82 Version {
83 /// The version number found
84 num: u32,
85 /// The range of bytes that were parsed to consume the header of the
86 /// module. Note that this range is relative to the start of the byte
87 /// stream.
88 range: Range,
89 },
90
91 /// A type section was received, and the provided reader can be used to
92 /// parse the contents of the type section.
93 TypeSection(crate::TypeSectionReader<'a>),
94 /// A import section was received, and the provided reader can be used to
95 /// parse the contents of the import section.
96 ImportSection(crate::ImportSectionReader<'a>),
97 /// An alias section was received, and the provided reader can be used to
98 /// parse the contents of the alias section.
99 AliasSection(crate::AliasSectionReader<'a>),
100 /// An instance section was received, and the provided reader can be used to
101 /// parse the contents of the instance section.
102 InstanceSection(crate::InstanceSectionReader<'a>),
103 /// A function section was received, and the provided reader can be used to
104 /// parse the contents of the function section.
105 FunctionSection(crate::FunctionSectionReader<'a>),
106 /// A table section was received, and the provided reader can be used to
107 /// parse the contents of the table section.
108 TableSection(crate::TableSectionReader<'a>),
109 /// A memory section was received, and the provided reader can be used to
110 /// parse the contents of the memory section.
111 MemorySection(crate::MemorySectionReader<'a>),
112 /// An event section was received, and the provided reader can be used to
113 /// parse the contents of the event section.
114 EventSection(crate::EventSectionReader<'a>),
115 /// A global section was received, and the provided reader can be used to
116 /// parse the contents of the global section.
117 GlobalSection(crate::GlobalSectionReader<'a>),
118 /// An export section was received, and the provided reader can be used to
119 /// parse the contents of the export section.
120 ExportSection(crate::ExportSectionReader<'a>),
121 /// A start section was received, and the `u32` here is the index of the
122 /// start function.
123 StartSection {
124 /// The start function index
125 func: u32,
126 /// The range of bytes that specify the `func` field, specified in
127 /// offsets relative to the start of the byte stream.
128 range: Range,
129 },
130 /// An element section was received, and the provided reader can be used to
131 /// parse the contents of the element section.
132 ElementSection(crate::ElementSectionReader<'a>),
133 /// A data count section was received, and the `u32` here is the contents of
134 /// the data count section.
135 DataCountSection {
136 /// The number of data segments.
137 count: u32,
138 /// The range of bytes that specify the `count` field, specified in
139 /// offsets relative to the start of the byte stream.
140 range: Range,
141 },
142 /// A data section was received, and the provided reader can be used to
143 /// parse the contents of the data section.
144 DataSection(crate::DataSectionReader<'a>),
145 /// A custom section was found.
146 CustomSection {
147 /// The name of the custom section.
148 name: &'a str,
149 /// The offset, relative to the start of the original module, that the
150 /// `data` payload for this custom section starts at.
151 data_offset: usize,
152 /// The actual contents of the custom section.
153 data: &'a [u8],
154 /// The range of bytes that specify this whole custom section (including
155 /// both the name of this custom section and its data) specified in
156 /// offsets relative to the start of the byte stream.
157 range: Range,
158 },
159
160 /// Indicator of the start of the code section.
161 ///
162 /// This entry is returned whenever the code section starts. The `count`
163 /// field indicates how many entries are in this code section. After
164 /// receiving this start marker you're guaranteed that the next `count`
165 /// items will be either `CodeSectionEntry` or an error will be returned.
166 ///
167 /// This, unlike other sections, is intended to be used for streaming the
168 /// contents of the code section. The code section is not required to be
169 /// fully resident in memory when we parse it. Instead a [`Parser`] is
170 /// capable of parsing piece-by-piece of a code section.
171 CodeSectionStart {
172 /// The number of functions in this section.
173 count: u32,
174 /// The range of bytes that represent this section, specified in
175 /// offsets relative to the start of the byte stream.
176 range: Range,
177 /// The size, in bytes, of the remaining contents of this section.
178 ///
179 /// This can be used in combination with [`Parser::skip_section`]
180 /// where the caller will know how many bytes to skip before feeding
181 /// bytes into `Parser` again.
182 size: u32,
183 },
184
185 /// An entry of the code section, a function, was parsed.
186 ///
187 /// This entry indicates that a function was successfully received from the
188 /// code section, and the payload here is the window into the original input
189 /// where the function resides. Note that the function itself has not been
190 /// parsed, it's only been outlined. You'll need to process the
191 /// `FunctionBody` provided to test whether it parses and/or is valid.
192 CodeSectionEntry(crate::FunctionBody<'a>),
193
194 /// Indicator of the start of the module code section.
195 ///
196 /// This behaves the same as the `CodeSectionStart` payload being returned.
197 /// You're guaranteed the next `count` items will be of type
198 /// `ModuleSectionEntry`.
199 ModuleSectionStart {
200 /// The number of inline modules in this section.
201 count: u32,
202 /// The range of bytes that represent this section, specified in
203 /// offsets relative to the start of the byte stream.
204 range: Range,
205 /// The size, in bytes, of the remaining contents of this section.
206 size: u32,
207 },
208
209 /// An entry of the module code section, a module, was parsed.
210 ///
211 /// This variant is special in that it returns a sub-`Parser`. Upon
212 /// receiving a `ModuleSectionEntry` it is expected that the returned
213 /// `Parser` will be used instead of the parent `Parser` until the parse has
214 /// finished. You'll need to feed data into the `Parser` returned until it
215 /// returns `Payload::End`. After that you'll switch back to the parent
216 /// parser to resume parsing the rest of the module code section.
217 ///
218 /// Note that binaries will not be parsed correctly if you feed the data for
219 /// a nested module into the parent [`Parser`].
220 ModuleSectionEntry {
221 /// The parser to use to parse the contents of the nested submodule.
222 /// This parser should be used until it reports `End`.
223 parser: Parser,
224 /// The range of bytes, relative to the start of the input stream, of
225 /// the bytes containing this submodule.
226 range: Range,
227 },
228
229 /// An unknown section was found.
230 ///
231 /// This variant is returned for all unknown sections in a wasm file. This
232 /// likely wants to be interpreted as an error by consumers of the parser,
233 /// but this can also be used to parse sections unknown to wasmparser at
234 /// this time.
235 UnknownSection {
236 /// The 8-bit identifier for this section.
237 id: u8,
238 /// The contents of this section.
239 contents: &'a [u8],
240 /// The range of bytes, relative to the start of the original data
241 /// stream, that the contents of this section reside in.
242 range: Range,
243 },
244
245 /// The end of the WebAssembly module was reached.
246 End,
247 }
248
249 impl Parser {
250 /// Creates a new module parser.
251 ///
252 /// Reports errors and ranges relative to `offset` provided, where `offset`
253 /// is some logical offset within the input stream that we're parsing.
new(offset: u64) -> Parser254 pub fn new(offset: u64) -> Parser {
255 Parser {
256 state: State::ModuleHeader,
257 offset,
258 max_size: u64::max_value(),
259 }
260 }
261
262 /// Attempts to parse a chunk of data.
263 ///
264 /// This method will attempt to parse the next incremental portion of a
265 /// WebAssembly binary. Data available for the module is provided as `data`,
266 /// and the data can be incomplete if more data has yet to arrive for the
267 /// module. The `eof` flag indicates whether `data` represents all possible
268 /// data for the module and no more data will ever be received.
269 ///
270 /// There are two ways parsing can succeed with this method:
271 ///
272 /// * `Chunk::NeedMoreData` - this indicates that there is not enough bytes
273 /// in `data` to parse a chunk of this module. The caller needs to wait
274 /// for more data to be available in this situation before calling this
275 /// method again. It is guaranteed that this is only returned if `eof` is
276 /// `false`.
277 ///
278 /// * `Chunk::Parsed` - this indicates that a chunk of the input was
279 /// successfully parsed. The payload is available in this variant of what
280 /// was parsed, and this also indicates how many bytes of `data` was
281 /// consumed. It's expected that the caller will not provide these bytes
282 /// back to the [`Parser`] again.
283 ///
284 /// Note that all `Chunk` return values are connected, with a lifetime, to
285 /// the input buffer. Each parsed chunk borrows the input buffer and is a
286 /// view into it for successfully parsed chunks.
287 ///
288 /// It is expected that you'll call this method until `Payload::End` is
289 /// reached, at which point you're guaranteed that the module has completely
290 /// parsed. Note that complete parsing, for the top-level wasm module,
291 /// implies that `data` is empty and `eof` is `true`.
292 ///
293 /// # Errors
294 ///
295 /// Parse errors are returned as an `Err`. Errors can happen when the
296 /// structure of the module is unexpected, or if sections are too large for
297 /// example. Note that errors are not returned for malformed *contents* of
298 /// sections here. Sections are generally not individually parsed and each
299 /// returned [`Payload`] needs to be iterated over further to detect all
300 /// errors.
301 ///
302 /// # Examples
303 ///
304 /// An example of reading a wasm file from a stream (`std::io::Read`) and
305 /// incrementally parsing it.
306 ///
307 /// ```
308 /// use std::io::Read;
309 /// use anyhow::Result;
310 /// use wasmparser::{Parser, Chunk, Payload::*};
311 ///
312 /// fn parse(mut reader: impl Read) -> Result<()> {
313 /// let mut buf = Vec::new();
314 /// let mut parser = Parser::new(0);
315 /// let mut eof = false;
316 /// let mut stack = Vec::new();
317 ///
318 /// loop {
319 /// let (payload, consumed) = match parser.parse(&buf, eof)? {
320 /// Chunk::NeedMoreData(hint) => {
321 /// assert!(!eof); // otherwise an error would be returned
322 ///
323 /// // Use the hint to preallocate more space, then read
324 /// // some more data into our buffer.
325 /// //
326 /// // Note that the buffer management here is not ideal,
327 /// // but it's compact enough to fit in an example!
328 /// let len = buf.len();
329 /// buf.extend((0..hint).map(|_| 0u8));
330 /// let n = reader.read(&mut buf[len..])?;
331 /// buf.truncate(len + n);
332 /// eof = n == 0;
333 /// continue;
334 /// }
335 ///
336 /// Chunk::Parsed { consumed, payload } => (payload, consumed),
337 /// };
338 ///
339 /// match payload {
340 /// // Each of these would be handled individually as necessary
341 /// Version { .. } => { /* ... */ }
342 /// TypeSection(_) => { /* ... */ }
343 /// ImportSection(_) => { /* ... */ }
344 /// AliasSection(_) => { /* ... */ }
345 /// InstanceSection(_) => { /* ... */ }
346 /// FunctionSection(_) => { /* ... */ }
347 /// TableSection(_) => { /* ... */ }
348 /// MemorySection(_) => { /* ... */ }
349 /// EventSection(_) => { /* ... */ }
350 /// GlobalSection(_) => { /* ... */ }
351 /// ExportSection(_) => { /* ... */ }
352 /// StartSection { .. } => { /* ... */ }
353 /// ElementSection(_) => { /* ... */ }
354 /// DataCountSection { .. } => { /* ... */ }
355 /// DataSection(_) => { /* ... */ }
356 ///
357 /// // Here we know how many functions we'll be receiving as
358 /// // `CodeSectionEntry`, so we can prepare for that, and
359 /// // afterwards we can parse and handle each function
360 /// // individually.
361 /// CodeSectionStart { .. } => { /* ... */ }
362 /// CodeSectionEntry(body) => {
363 /// // here we can iterate over `body` to parse the function
364 /// // and its locals
365 /// }
366 ///
367 /// // When parsing nested modules we need to switch which
368 /// // `Parser` we're using.
369 /// ModuleSectionStart { .. } => { /* ... */ }
370 /// ModuleSectionEntry { parser: subparser, .. } => {
371 /// stack.push(parser);
372 /// parser = subparser;
373 /// }
374 ///
375 /// CustomSection { name, .. } => { /* ... */ }
376 ///
377 /// // most likely you'd return an error here
378 /// UnknownSection { id, .. } => { /* ... */ }
379 ///
380 /// // Once we've reached the end of a module we either resume
381 /// // at the parent module or we break out of the loop because
382 /// // we're done.
383 /// End => {
384 /// if let Some(parent_parser) = stack.pop() {
385 /// parser = parent_parser;
386 /// } else {
387 /// break;
388 /// }
389 /// }
390 /// }
391 ///
392 /// // once we're done processing the payload we can forget the
393 /// // original.
394 /// buf.drain(..consumed);
395 /// }
396 ///
397 /// Ok(())
398 /// }
399 ///
400 /// # parse(&b"\0asm\x01\0\0\0"[..]).unwrap();
401 /// ```
parse<'a>(&mut self, data: &'a [u8], eof: bool) -> Result<Chunk<'a>>402 pub fn parse<'a>(&mut self, data: &'a [u8], eof: bool) -> Result<Chunk<'a>> {
403 let (data, eof) = if usize_to_u64(data.len()) > self.max_size {
404 (&data[..(self.max_size as usize)], true)
405 } else {
406 (data, eof)
407 };
408 // TODO: thread through `offset: u64` to `BinaryReader`, remove
409 // the cast here.
410 let mut reader = BinaryReader::new_with_offset(data, self.offset as usize);
411 match self.parse_reader(&mut reader, eof) {
412 Ok(payload) => {
413 // Be sure to update our offset with how far we got in the
414 // reader
415 self.offset += usize_to_u64(reader.position);
416 self.max_size -= usize_to_u64(reader.position);
417 Ok(Chunk::Parsed {
418 consumed: reader.position,
419 payload,
420 })
421 }
422 Err(e) => {
423 // If we're at EOF then there's no way we can recover from any
424 // error, so continue to propagate it.
425 if eof {
426 return Err(e);
427 }
428
429 // If our error doesn't look like it can be resolved with more
430 // data being pulled down, then propagate it, otherwise switch
431 // the error to "feed me please"
432 match e.inner.needed_hint {
433 Some(hint) => Ok(Chunk::NeedMoreData(usize_to_u64(hint))),
434 None => Err(e),
435 }
436 }
437 }
438 }
439
parse_reader<'a>( &mut self, reader: &mut BinaryReader<'a>, eof: bool, ) -> Result<Payload<'a>>440 fn parse_reader<'a>(
441 &mut self,
442 reader: &mut BinaryReader<'a>,
443 eof: bool,
444 ) -> Result<Payload<'a>> {
445 use Payload::*;
446
447 match self.state {
448 State::ModuleHeader => {
449 let start = reader.original_position();
450 let num = reader.read_file_header()?;
451 self.state = State::SectionStart;
452 Ok(Version {
453 num,
454 range: Range {
455 start,
456 end: reader.original_position(),
457 },
458 })
459 }
460 State::SectionStart => {
461 // If we're at eof and there are no bytes in our buffer, then
462 // that means we reached the end of the wasm file since it's
463 // just a bunch of sections concatenated after the module
464 // header.
465 if eof && reader.bytes_remaining() == 0 {
466 return Ok(Payload::End);
467 }
468
469 let id = reader.read_var_u7()? as u8;
470 let len_pos = reader.position;
471 let mut len = reader.read_var_u32()?;
472
473 // Test to make sure that this section actually fits within
474 // `Parser::max_size`. This doesn't matter for top-level modules
475 // but it is required for nested modules to correctly ensure
476 // that all sections live entirely within their section of the
477 // file.
478 let section_overflow = self
479 .max_size
480 .checked_sub(usize_to_u64(reader.position))
481 .and_then(|s| s.checked_sub(len.into()))
482 .is_none();
483 if section_overflow {
484 return Err(BinaryReaderError::new("section too large", len_pos));
485 }
486
487 match id {
488 0 => {
489 let start = reader.original_position();
490 let range = Range {
491 start,
492 end: reader.original_position() + len as usize,
493 };
494 let mut content = subreader(reader, len)?;
495 // Note that if this fails we can't read any more bytes,
496 // so clear the "we'd succeed if we got this many more
497 // bytes" because we can't recover from "eof" at this point.
498 let name = content.read_string().map_err(clear_hint)?;
499 Ok(Payload::CustomSection {
500 name,
501 data_offset: content.original_position(),
502 data: content.remaining_buffer(),
503 range,
504 })
505 }
506 1 => section(reader, len, TypeSectionReader::new, TypeSection),
507 2 => section(reader, len, ImportSectionReader::new, ImportSection),
508 3 => section(reader, len, FunctionSectionReader::new, FunctionSection),
509 4 => section(reader, len, TableSectionReader::new, TableSection),
510 5 => section(reader, len, MemorySectionReader::new, MemorySection),
511 6 => section(reader, len, GlobalSectionReader::new, GlobalSection),
512 7 => section(reader, len, ExportSectionReader::new, ExportSection),
513 8 => {
514 let (func, range) = single_u32(reader, len, "start")?;
515 Ok(StartSection { func, range })
516 }
517 9 => section(reader, len, ElementSectionReader::new, ElementSection),
518 10 => {
519 let start = reader.original_position();
520 let count = delimited(reader, &mut len, |r| r.read_var_u32())?;
521 let range = Range {
522 start,
523 end: reader.original_position() + len as usize,
524 };
525 self.state = State::FunctionBody {
526 remaining: count,
527 len,
528 };
529 Ok(CodeSectionStart {
530 count,
531 range,
532 size: len,
533 })
534 }
535 11 => section(reader, len, DataSectionReader::new, DataSection),
536 12 => {
537 let (count, range) = single_u32(reader, len, "data count")?;
538 Ok(DataCountSection { count, range })
539 }
540 13 => section(reader, len, EventSectionReader::new, EventSection),
541 14 => {
542 let start = reader.original_position();
543 let count = delimited(reader, &mut len, |r| r.read_var_u32())?;
544 let range = Range {
545 start,
546 end: reader.original_position() + len as usize,
547 };
548 self.state = State::Module {
549 remaining: count,
550 len,
551 };
552 Ok(ModuleSectionStart {
553 count,
554 range,
555 size: len,
556 })
557 }
558 15 => section(reader, len, InstanceSectionReader::new, InstanceSection),
559 16 => section(reader, len, AliasSectionReader::new, AliasSection),
560 id => {
561 let offset = reader.original_position();
562 let contents = reader.read_bytes(len as usize)?;
563 let range = Range {
564 start: offset,
565 end: offset + len as usize,
566 };
567 Ok(UnknownSection {
568 id,
569 contents,
570 range,
571 })
572 }
573 }
574 }
575
576 // Once we hit 0 remaining incrementally parsed items, with 0
577 // remaining bytes in each section, we're done and can switch back
578 // to parsing sections.
579 State::FunctionBody {
580 remaining: 0,
581 len: 0,
582 }
583 | State::Module {
584 remaining: 0,
585 len: 0,
586 } => {
587 self.state = State::SectionStart;
588 self.parse_reader(reader, eof)
589 }
590
591 // ... otherwise trailing bytes with no remaining entries in these
592 // sections indicates an error.
593 State::FunctionBody { remaining: 0, len } | State::Module { remaining: 0, len } => {
594 debug_assert!(len > 0);
595 let offset = reader.original_position();
596 Err(BinaryReaderError::new(
597 "trailing bytes at end of section",
598 offset,
599 ))
600 }
601
602 // Functions are relatively easy to parse when we know there's at
603 // least one remaining and at least one byte available to read
604 // things.
605 //
606 // We use the remaining length try to read a u32 size of the
607 // function, and using that size we require the entire function be
608 // resident in memory. This means that we're reading whole chunks of
609 // functions at a time.
610 //
611 // Limiting via `Parser::max_size` (nested modules) happens above in
612 // `fn parse`, and limiting by our section size happens via
613 // `delimited`. Actual parsing of the function body is delegated to
614 // the caller to iterate over the `FunctionBody` structure.
615 State::FunctionBody { remaining, mut len } => {
616 let body = delimited(reader, &mut len, |r| {
617 let size = r.read_var_u32()?;
618 let offset = r.original_position();
619 Ok(FunctionBody::new(offset, r.read_bytes(size as usize)?))
620 })?;
621 self.state = State::FunctionBody {
622 remaining: remaining - 1,
623 len,
624 };
625 Ok(CodeSectionEntry(body))
626 }
627
628 // Modules are trickier than functions. What's going to happen here
629 // is that we'll be offloading parsing to a sub-`Parser`. This
630 // sub-`Parser` will be delimited to not read past the size of the
631 // module that's specified.
632 //
633 // So the first thing that happens here is we read the size of the
634 // module. We use `delimited` to make sure the bytes specifying the
635 // size of the module are themselves within the module code section.
636 //
637 // Once we've read the size of a module, however, there's a few
638 // pieces of state that we need to update. We as a parser will not
639 // receive the next `size` bytes, so we need to update our internal
640 // bookkeeping to account for that:
641 //
642 // * The `len`, number of bytes remaining in this section, is
643 // decremented by `size`. This can underflow, however, meaning
644 // that the size of the module doesn't fit within the section.
645 //
646 // * Our `Parser::max_size` field needs to account for the bytes
647 // that we're reading. Note that this is guaranteed to not
648 // underflow, however, because whenever we parse a section header
649 // we guarantee that its contents fit within our `max_size`.
650 //
651 // To update `len` we do that when updating `self.state`, and to
652 // update `max_size` we do that inline. Note that this will get
653 // further tweaked after we return with the bytes we read specifying
654 // the size of the module itself.
655 State::Module { remaining, mut len } => {
656 let size = delimited(reader, &mut len, |r| r.read_var_u32())?;
657 match len.checked_sub(size) {
658 Some(i) => len = i,
659 None => {
660 return Err(BinaryReaderError::new(
661 "Unexpected EOF",
662 reader.original_position(),
663 ));
664 }
665 }
666 self.state = State::Module {
667 remaining: remaining - 1,
668 len,
669 };
670 let range = Range {
671 start: reader.original_position(),
672 end: reader.original_position() + size as usize,
673 };
674 self.max_size -= u64::from(size);
675 self.offset += u64::from(size);
676 let mut parser = Parser::new(usize_to_u64(reader.original_position()));
677 parser.max_size = size.into();
678 Ok(ModuleSectionEntry { parser, range })
679 }
680 }
681 }
682
683 /// Convenience function that can be used to parse a module entirely
684 /// resident in memory.
685 ///
686 /// This function will parse the `data` provided as a WebAssembly module,
687 /// assuming that `data` represents the entire WebAssembly module.
688 ///
689 /// Note that when this function yields `ModuleSectionEntry`
690 /// no action needs to be taken with the returned parser. The parser will be
691 /// automatically switched to internally and more payloads will continue to
692 /// get returned.
parse_all<'a>( self, mut data: &'a [u8], ) -> impl Iterator<Item = Result<Payload<'a>>> + 'a693 pub fn parse_all<'a>(
694 self,
695 mut data: &'a [u8],
696 ) -> impl Iterator<Item = Result<Payload<'a>>> + 'a {
697 let mut stack = Vec::new();
698 let mut cur = self;
699 let mut done = false;
700 iter::from_fn(move || {
701 if done {
702 return None;
703 }
704 let payload = match cur.parse(data, true) {
705 // Propagate all errors
706 Err(e) => return Some(Err(e)),
707
708 // This isn't possible because `eof` is always true.
709 Ok(Chunk::NeedMoreData(_)) => unreachable!(),
710
711 Ok(Chunk::Parsed { payload, consumed }) => {
712 data = &data[consumed..];
713 payload
714 }
715 };
716
717 match &payload {
718 // If a module ends then we either finished the current
719 // module or, if there's a parent, we switch back to
720 // resuming parsing the parent.
721 Payload::End => match stack.pop() {
722 Some(p) => cur = p,
723 None => done = true,
724 },
725
726 // When we enter a nested module then we need to update our
727 // current parser, saving off the previous state.
728 //
729 // Afterwards we turn the loop again to recurse in parsing the
730 // nested module.
731 Payload::ModuleSectionEntry { parser, range: _ } => {
732 stack.push(cur.clone());
733 cur = parser.clone();
734 }
735
736 _ => {}
737 }
738
739 Some(Ok(payload))
740 })
741 }
742
743 /// Skip parsing the code or module code section entirely.
744 ///
745 /// This function can be used to indicate, after receiving
746 /// `CodeSectionStart` or `ModuleSectionStart`, that the section
747 /// will not be parsed.
748 ///
749 /// The caller will be responsible for skipping `size` bytes (found in the
750 /// `CodeSectionStart` or `ModuleSectionStart` payload). Bytes should
751 /// only be fed into `parse` after the `size` bytes have been skipped.
752 ///
753 /// # Panics
754 ///
755 /// This function will panic if the parser is not in a state where it's
756 /// parsing the code or module code section.
757 ///
758 /// # Examples
759 ///
760 /// ```
761 /// use wasmparser::{Result, Parser, Chunk, Range, SectionReader, Payload::*};
762 ///
763 /// fn objdump_headers(mut wasm: &[u8]) -> Result<()> {
764 /// let mut parser = Parser::new(0);
765 /// loop {
766 /// let payload = match parser.parse(wasm, true)? {
767 /// Chunk::Parsed { consumed, payload } => {
768 /// wasm = &wasm[consumed..];
769 /// payload
770 /// }
771 /// // this state isn't possible with `eof = true`
772 /// Chunk::NeedMoreData(_) => unreachable!(),
773 /// };
774 /// match payload {
775 /// TypeSection(s) => print_range("type section", &s.range()),
776 /// ImportSection(s) => print_range("import section", &s.range()),
777 /// // .. other sections
778 ///
779 /// // Print the range of the code section we see, but don't
780 /// // actually iterate over each individual function.
781 /// CodeSectionStart { range, size, .. } => {
782 /// print_range("code section", &range);
783 /// parser.skip_section();
784 /// wasm = &wasm[size as usize..];
785 /// }
786 /// End => break,
787 /// _ => {}
788 /// }
789 /// }
790 /// Ok(())
791 /// }
792 ///
793 /// fn print_range(section: &str, range: &Range) {
794 /// println!("{:>40}: {:#010x} - {:#010x}", section, range.start, range.end);
795 /// }
796 /// ```
skip_section(&mut self)797 pub fn skip_section(&mut self) {
798 let skip = match self.state {
799 State::FunctionBody { remaining: _, len } | State::Module { remaining: _, len } => len,
800 _ => panic!("wrong state to call `skip_section`"),
801 };
802 self.offset += u64::from(skip);
803 self.max_size -= u64::from(skip);
804 self.state = State::SectionStart;
805 }
806 }
807
usize_to_u64(a: usize) -> u64808 fn usize_to_u64(a: usize) -> u64 {
809 a.try_into().unwrap()
810 }
811
812 /// Parses an entire section resident in memory into a `Payload`.
813 ///
814 /// Requires that `len` bytes are resident in `reader` and uses `ctor`/`variant`
815 /// to construct the section to return.
section<'a, T>( reader: &mut BinaryReader<'a>, len: u32, ctor: fn(&'a [u8], usize) -> Result<T>, variant: fn(T) -> Payload<'a>, ) -> Result<Payload<'a>>816 fn section<'a, T>(
817 reader: &mut BinaryReader<'a>,
818 len: u32,
819 ctor: fn(&'a [u8], usize) -> Result<T>,
820 variant: fn(T) -> Payload<'a>,
821 ) -> Result<Payload<'a>> {
822 let offset = reader.original_position();
823 let payload = reader.read_bytes(len as usize)?;
824 // clear the hint for "need this many more bytes" here because we already
825 // read all the bytes, so it's not possible to read more bytes if this
826 // fails.
827 let reader = ctor(payload, offset).map_err(clear_hint)?;
828 Ok(variant(reader))
829 }
830
831 /// Creates a new `BinaryReader` from the given `reader` which will be reading
832 /// the first `len` bytes.
833 ///
834 /// This means that `len` bytes must be resident in memory at the time of this
835 /// reading.
subreader<'a>(reader: &mut BinaryReader<'a>, len: u32) -> Result<BinaryReader<'a>>836 fn subreader<'a>(reader: &mut BinaryReader<'a>, len: u32) -> Result<BinaryReader<'a>> {
837 let offset = reader.original_position();
838 let payload = reader.read_bytes(len as usize)?;
839 Ok(BinaryReader::new_with_offset(payload, offset))
840 }
841
842 /// Reads a section that is represented by a single uleb-encoded `u32`.
single_u32<'a>(reader: &mut BinaryReader<'a>, len: u32, desc: &str) -> Result<(u32, Range)>843 fn single_u32<'a>(reader: &mut BinaryReader<'a>, len: u32, desc: &str) -> Result<(u32, Range)> {
844 let range = Range {
845 start: reader.original_position(),
846 end: reader.original_position() + len as usize,
847 };
848 let mut content = subreader(reader, len)?;
849 // We can't recover from "unexpected eof" here because our entire section is
850 // already resident in memory, so clear the hint for how many more bytes are
851 // expected.
852 let index = content.read_var_u32().map_err(clear_hint)?;
853 if !content.eof() {
854 return Err(BinaryReaderError::new(
855 format!("Unexpected content in the {} section", desc),
856 content.original_position(),
857 ));
858 }
859 Ok((index, range))
860 }
861
862 /// Attempts to parse using `f`.
863 ///
864 /// This will update `*len` with the number of bytes consumed, and it will cause
865 /// a failure to be returned instead of the number of bytes consumed exceeds
866 /// what `*len` currently is.
delimited<'a, T>( reader: &mut BinaryReader<'a>, len: &mut u32, f: impl FnOnce(&mut BinaryReader<'a>) -> Result<T>, ) -> Result<T>867 fn delimited<'a, T>(
868 reader: &mut BinaryReader<'a>,
869 len: &mut u32,
870 f: impl FnOnce(&mut BinaryReader<'a>) -> Result<T>,
871 ) -> Result<T> {
872 let start = reader.position;
873 let ret = f(reader)?;
874 *len = match (reader.position - start)
875 .try_into()
876 .ok()
877 .and_then(|i| len.checked_sub(i))
878 {
879 Some(i) => i,
880 None => return Err(BinaryReaderError::new("Unexpected EOF", start)),
881 };
882 Ok(ret)
883 }
884
885 impl Default for Parser {
default() -> Parser886 fn default() -> Parser {
887 Parser::new(0)
888 }
889 }
890
891 impl fmt::Debug for Payload<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result892 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
893 use Payload::*;
894 match self {
895 CustomSection {
896 name,
897 data_offset,
898 data: _,
899 range,
900 } => f
901 .debug_struct("CustomSection")
902 .field("name", name)
903 .field("data_offset", data_offset)
904 .field("range", range)
905 .field("data", &"...")
906 .finish(),
907 Version { num, range } => f
908 .debug_struct("Version")
909 .field("num", num)
910 .field("range", range)
911 .finish(),
912 TypeSection(_) => f.debug_tuple("TypeSection").field(&"...").finish(),
913 ImportSection(_) => f.debug_tuple("ImportSection").field(&"...").finish(),
914 AliasSection(_) => f.debug_tuple("AliasSection").field(&"...").finish(),
915 InstanceSection(_) => f.debug_tuple("InstanceSection").field(&"...").finish(),
916 FunctionSection(_) => f.debug_tuple("FunctionSection").field(&"...").finish(),
917 TableSection(_) => f.debug_tuple("TableSection").field(&"...").finish(),
918 MemorySection(_) => f.debug_tuple("MemorySection").field(&"...").finish(),
919 EventSection(_) => f.debug_tuple("EventSection").field(&"...").finish(),
920 GlobalSection(_) => f.debug_tuple("GlobalSection").field(&"...").finish(),
921 ExportSection(_) => f.debug_tuple("ExportSection").field(&"...").finish(),
922 ElementSection(_) => f.debug_tuple("ElementSection").field(&"...").finish(),
923 DataSection(_) => f.debug_tuple("DataSection").field(&"...").finish(),
924 StartSection { func, range } => f
925 .debug_struct("StartSection")
926 .field("func", func)
927 .field("range", range)
928 .finish(),
929 DataCountSection { count, range } => f
930 .debug_struct("DataCountSection")
931 .field("count", count)
932 .field("range", range)
933 .finish(),
934 CodeSectionStart { count, range, size } => f
935 .debug_struct("CodeSectionStart")
936 .field("count", count)
937 .field("range", range)
938 .field("size", size)
939 .finish(),
940 CodeSectionEntry(_) => f.debug_tuple("CodeSectionEntry").field(&"...").finish(),
941 ModuleSectionStart { count, range, size } => f
942 .debug_struct("ModuleSectionStart")
943 .field("count", count)
944 .field("range", range)
945 .field("size", size)
946 .finish(),
947 ModuleSectionEntry { parser: _, range } => f
948 .debug_struct("ModuleSectionEntry")
949 .field("range", range)
950 .finish(),
951 UnknownSection { id, range, .. } => f
952 .debug_struct("UnknownSection")
953 .field("id", id)
954 .field("range", range)
955 .finish(),
956 End => f.write_str("End"),
957 }
958 }
959 }
960
clear_hint(mut err: BinaryReaderError) -> BinaryReaderError961 fn clear_hint(mut err: BinaryReaderError) -> BinaryReaderError {
962 err.inner.needed_hint = None;
963 err
964 }
965
966 #[cfg(test)]
967 mod tests {
968 use super::*;
969
970 macro_rules! assert_matches {
971 ($a:expr, $b:pat $(,)?) => {
972 match $a {
973 $b => {}
974 a => panic!("`{:?}` doesn't match `{}`", a, stringify!($b)),
975 }
976 };
977 }
978
979 #[test]
header()980 fn header() {
981 assert!(Parser::default().parse(&[], true).is_err());
982 assert_matches!(
983 Parser::default().parse(&[], false),
984 Ok(Chunk::NeedMoreData(4)),
985 );
986 assert_matches!(
987 Parser::default().parse(b"\0", false),
988 Ok(Chunk::NeedMoreData(3)),
989 );
990 assert_matches!(
991 Parser::default().parse(b"\0asm", false),
992 Ok(Chunk::NeedMoreData(4)),
993 );
994 assert_matches!(
995 Parser::default().parse(b"\0asm\x01\0\0\0", false),
996 Ok(Chunk::Parsed {
997 consumed: 8,
998 payload: Payload::Version { num: 1, .. },
999 }),
1000 );
1001 }
1002
parser_after_header() -> Parser1003 fn parser_after_header() -> Parser {
1004 let mut p = Parser::default();
1005 assert_matches!(
1006 p.parse(b"\0asm\x01\0\0\0", false),
1007 Ok(Chunk::Parsed {
1008 consumed: 8,
1009 payload: Payload::Version { num: 1, .. },
1010 }),
1011 );
1012 return p;
1013 }
1014
1015 #[test]
start_section()1016 fn start_section() {
1017 assert_matches!(
1018 parser_after_header().parse(&[], false),
1019 Ok(Chunk::NeedMoreData(1)),
1020 );
1021 assert!(parser_after_header().parse(&[8], true).is_err());
1022 assert!(parser_after_header().parse(&[8, 1], true).is_err());
1023 assert!(parser_after_header().parse(&[8, 2], true).is_err());
1024 assert_matches!(
1025 parser_after_header().parse(&[8], false),
1026 Ok(Chunk::NeedMoreData(1)),
1027 );
1028 assert_matches!(
1029 parser_after_header().parse(&[8, 1], false),
1030 Ok(Chunk::NeedMoreData(1)),
1031 );
1032 assert_matches!(
1033 parser_after_header().parse(&[8, 2], false),
1034 Ok(Chunk::NeedMoreData(2)),
1035 );
1036 assert_matches!(
1037 parser_after_header().parse(&[8, 1, 1], false),
1038 Ok(Chunk::Parsed {
1039 consumed: 3,
1040 payload: Payload::StartSection { func: 1, .. },
1041 }),
1042 );
1043 assert!(parser_after_header().parse(&[8, 2, 1, 1], false).is_err());
1044 assert!(parser_after_header().parse(&[8, 0], false).is_err());
1045 }
1046
1047 #[test]
end_works()1048 fn end_works() {
1049 assert_matches!(
1050 parser_after_header().parse(&[], true),
1051 Ok(Chunk::Parsed {
1052 consumed: 0,
1053 payload: Payload::End,
1054 }),
1055 );
1056 }
1057
1058 #[test]
type_section()1059 fn type_section() {
1060 assert!(parser_after_header().parse(&[1], true).is_err());
1061 assert!(parser_after_header().parse(&[1, 0], false).is_err());
1062 // assert!(parser_after_header().parse(&[8, 2], true).is_err());
1063 assert_matches!(
1064 parser_after_header().parse(&[1], false),
1065 Ok(Chunk::NeedMoreData(1)),
1066 );
1067 assert_matches!(
1068 parser_after_header().parse(&[1, 1], false),
1069 Ok(Chunk::NeedMoreData(1)),
1070 );
1071 assert_matches!(
1072 parser_after_header().parse(&[1, 1, 1], false),
1073 Ok(Chunk::Parsed {
1074 consumed: 3,
1075 payload: Payload::TypeSection(_),
1076 }),
1077 );
1078 assert_matches!(
1079 parser_after_header().parse(&[1, 1, 1, 2, 3, 4], false),
1080 Ok(Chunk::Parsed {
1081 consumed: 3,
1082 payload: Payload::TypeSection(_),
1083 }),
1084 );
1085 }
1086
1087 #[test]
custom_section()1088 fn custom_section() {
1089 assert!(parser_after_header().parse(&[0], true).is_err());
1090 assert!(parser_after_header().parse(&[0, 0], false).is_err());
1091 assert!(parser_after_header().parse(&[0, 1, 1], false).is_err());
1092 assert_matches!(
1093 parser_after_header().parse(&[0, 2, 1], false),
1094 Ok(Chunk::NeedMoreData(1)),
1095 );
1096 assert_matches!(
1097 parser_after_header().parse(&[0, 1, 0], false),
1098 Ok(Chunk::Parsed {
1099 consumed: 3,
1100 payload: Payload::CustomSection {
1101 name: "",
1102 data_offset: 11,
1103 data: b"",
1104 range: Range { start: 10, end: 11 },
1105 },
1106 }),
1107 );
1108 assert_matches!(
1109 parser_after_header().parse(&[0, 2, 1, b'a'], false),
1110 Ok(Chunk::Parsed {
1111 consumed: 4,
1112 payload: Payload::CustomSection {
1113 name: "a",
1114 data_offset: 12,
1115 data: b"",
1116 range: Range { start: 10, end: 12 },
1117 },
1118 }),
1119 );
1120 assert_matches!(
1121 parser_after_header().parse(&[0, 2, 0, b'a'], false),
1122 Ok(Chunk::Parsed {
1123 consumed: 4,
1124 payload: Payload::CustomSection {
1125 name: "",
1126 data_offset: 11,
1127 data: b"a",
1128 range: Range { start: 10, end: 12 },
1129 },
1130 }),
1131 );
1132 }
1133
1134 #[test]
function_section()1135 fn function_section() {
1136 assert!(parser_after_header().parse(&[10], true).is_err());
1137 assert!(parser_after_header().parse(&[10, 0], true).is_err());
1138 assert!(parser_after_header().parse(&[10, 1], true).is_err());
1139 assert_matches!(
1140 parser_after_header().parse(&[10], false),
1141 Ok(Chunk::NeedMoreData(1))
1142 );
1143 assert_matches!(
1144 parser_after_header().parse(&[10, 1], false),
1145 Ok(Chunk::NeedMoreData(1))
1146 );
1147 let mut p = parser_after_header();
1148 assert_matches!(
1149 p.parse(&[10, 1, 0], false),
1150 Ok(Chunk::Parsed {
1151 consumed: 3,
1152 payload: Payload::CodeSectionStart { count: 0, .. },
1153 }),
1154 );
1155 assert_matches!(
1156 p.parse(&[], true),
1157 Ok(Chunk::Parsed {
1158 consumed: 0,
1159 payload: Payload::End,
1160 }),
1161 );
1162 let mut p = parser_after_header();
1163 assert_matches!(
1164 p.parse(&[10, 2, 1, 0], false),
1165 Ok(Chunk::Parsed {
1166 consumed: 3,
1167 payload: Payload::CodeSectionStart { count: 1, .. },
1168 }),
1169 );
1170 assert_matches!(
1171 p.parse(&[0], false),
1172 Ok(Chunk::Parsed {
1173 consumed: 1,
1174 payload: Payload::CodeSectionEntry(_),
1175 }),
1176 );
1177 assert_matches!(
1178 p.parse(&[], true),
1179 Ok(Chunk::Parsed {
1180 consumed: 0,
1181 payload: Payload::End,
1182 }),
1183 );
1184
1185 // 1 byte section with 1 function can't read the function body because
1186 // the section is too small
1187 let mut p = parser_after_header();
1188 assert_matches!(
1189 p.parse(&[10, 1, 1], false),
1190 Ok(Chunk::Parsed {
1191 consumed: 3,
1192 payload: Payload::CodeSectionStart { count: 1, .. },
1193 }),
1194 );
1195 assert_eq!(
1196 p.parse(&[0], false).unwrap_err().message(),
1197 "Unexpected EOF"
1198 );
1199
1200 // section with 2 functions but section is cut off
1201 let mut p = parser_after_header();
1202 assert_matches!(
1203 p.parse(&[10, 2, 2], false),
1204 Ok(Chunk::Parsed {
1205 consumed: 3,
1206 payload: Payload::CodeSectionStart { count: 2, .. },
1207 }),
1208 );
1209 assert_matches!(
1210 p.parse(&[0], false),
1211 Ok(Chunk::Parsed {
1212 consumed: 1,
1213 payload: Payload::CodeSectionEntry(_),
1214 }),
1215 );
1216 assert_matches!(p.parse(&[], false), Ok(Chunk::NeedMoreData(1)));
1217 assert_eq!(
1218 p.parse(&[0], false).unwrap_err().message(),
1219 "Unexpected EOF",
1220 );
1221
1222 // trailing data is bad
1223 let mut p = parser_after_header();
1224 assert_matches!(
1225 p.parse(&[10, 3, 1], false),
1226 Ok(Chunk::Parsed {
1227 consumed: 3,
1228 payload: Payload::CodeSectionStart { count: 1, .. },
1229 }),
1230 );
1231 assert_matches!(
1232 p.parse(&[0], false),
1233 Ok(Chunk::Parsed {
1234 consumed: 1,
1235 payload: Payload::CodeSectionEntry(_),
1236 }),
1237 );
1238 assert_eq!(
1239 p.parse(&[0], false).unwrap_err().message(),
1240 "trailing bytes at end of section",
1241 );
1242 }
1243
1244 #[test]
module_code_errors()1245 fn module_code_errors() {
1246 // no bytes to say size of section
1247 assert!(parser_after_header().parse(&[14], true).is_err());
1248 // section must start with a u32
1249 assert!(parser_after_header().parse(&[14, 0], true).is_err());
1250 // EOF before we finish reading the section
1251 assert!(parser_after_header().parse(&[14, 1], true).is_err());
1252 }
1253
1254 #[test]
module_code_one()1255 fn module_code_one() {
1256 let mut p = parser_after_header();
1257 assert_matches!(p.parse(&[14], false), Ok(Chunk::NeedMoreData(1)));
1258 assert_matches!(p.parse(&[14, 9], false), Ok(Chunk::NeedMoreData(1)));
1259 // Module code section, 10 bytes large, one module.
1260 assert_matches!(
1261 p.parse(&[14, 10, 1], false),
1262 Ok(Chunk::Parsed {
1263 consumed: 3,
1264 payload: Payload::ModuleSectionStart { count: 1, .. },
1265 })
1266 );
1267 // Declare an empty module, which will be 8 bytes large for the header.
1268 // Switch to the sub-parser on success.
1269 let mut sub = match p.parse(&[8], false) {
1270 Ok(Chunk::Parsed {
1271 consumed: 1,
1272 payload: Payload::ModuleSectionEntry { parser, .. },
1273 }) => parser,
1274 other => panic!("bad parse {:?}", other),
1275 };
1276
1277 // Parse the header of the submodule with the sub-parser.
1278 assert_matches!(sub.parse(&[], false), Ok(Chunk::NeedMoreData(4)));
1279 assert_matches!(sub.parse(b"\0asm", false), Ok(Chunk::NeedMoreData(4)));
1280 assert_matches!(
1281 sub.parse(b"\0asm\x01\0\0\0", false),
1282 Ok(Chunk::Parsed {
1283 consumed: 8,
1284 payload: Payload::Version { num: 1, .. },
1285 }),
1286 );
1287
1288 // The sub-parser should be byte-limited so the next byte shouldn't get
1289 // consumed, it's intended for the parent parser.
1290 assert_matches!(
1291 sub.parse(&[10], false),
1292 Ok(Chunk::Parsed {
1293 consumed: 0,
1294 payload: Payload::End,
1295 }),
1296 );
1297
1298 // The parent parser should now be back to resuming, and we simulate it
1299 // being done with bytes to ensure that it's safely at the end,
1300 // completing the module code section.
1301 assert_matches!(p.parse(&[], false), Ok(Chunk::NeedMoreData(1)));
1302 assert_matches!(
1303 p.parse(&[], true),
1304 Ok(Chunk::Parsed {
1305 consumed: 0,
1306 payload: Payload::End,
1307 }),
1308 );
1309 }
1310
1311 #[test]
nested_section_too_big()1312 fn nested_section_too_big() {
1313 let mut p = parser_after_header();
1314 // Module code section, 12 bytes large, one module. This leaves 11 bytes
1315 // of payload for the module definition itself.
1316 assert_matches!(
1317 p.parse(&[14, 12, 1], false),
1318 Ok(Chunk::Parsed {
1319 consumed: 3,
1320 payload: Payload::ModuleSectionStart { count: 1, .. },
1321 })
1322 );
1323 // Use one byte to say we're a 10 byte module, which fits exactly within
1324 // our module code section.
1325 let mut sub = match p.parse(&[10], false) {
1326 Ok(Chunk::Parsed {
1327 consumed: 1,
1328 payload: Payload::ModuleSectionEntry { parser, .. },
1329 }) => parser,
1330 other => panic!("bad parse {:?}", other),
1331 };
1332
1333 // use 8 bytes to parse the header, leaving 2 remaining bytes in our
1334 // module.
1335 assert_matches!(
1336 sub.parse(b"\0asm\x01\0\0\0", false),
1337 Ok(Chunk::Parsed {
1338 consumed: 8,
1339 payload: Payload::Version { num: 1, .. },
1340 }),
1341 );
1342
1343 // We can't parse a section which declares its bigger than the outer
1344 // module. This is section 1, one byte big, with one content byte. The
1345 // content byte, however, lives outside of the parent's module code
1346 // section.
1347 assert_eq!(
1348 sub.parse(&[1, 1, 0], false).unwrap_err().message(),
1349 "section too large",
1350 );
1351 }
1352 }
1353