Coverage Report

Created: 2026-09-14 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wasmparser/src/parser.rs
Line
Count
Source
1
#[cfg(feature = "features")]
2
use crate::WasmFeatures;
3
use crate::binary_reader::WASM_MAGIC_NUMBER;
4
use crate::offsets;
5
use crate::prelude::*;
6
use crate::{
7
    BinaryReader, CustomSectionReader, DataSectionReader, ElementSectionReader, Error,
8
    ExportSectionReader, FromReader, FunctionBody, FunctionSectionReader, GlobalSectionReader,
9
    ImportSectionReader, MemorySectionReader, Result, TableSectionReader, TagSectionReader,
10
    TypeSectionReader,
11
};
12
#[cfg(feature = "component-model")]
13
use crate::{
14
    ComponentCanonicalSectionReader, ComponentExportSectionReader, ComponentImportSectionReader,
15
    ComponentInstanceSectionReader, ComponentStartFunction, ComponentTypeSectionReader,
16
    CoreTypeSectionReader, InstanceSectionReader, SectionLimited, limits::MAX_WASM_MODULE_SIZE,
17
};
18
use core::fmt;
19
use core::iter;
20
use core::ops::Range;
21
22
pub(crate) const WASM_MODULE_VERSION: u16 = 0x1;
23
24
// Note that this started at `0xa` and we're incrementing up from there. When
25
// the component model is stabilized this will become 0x1. The changes here are:
26
//
27
// * [????-??-??] 0xa - original version
28
// * [2023-01-05] 0xb - `export` introduces an alias
29
// * [2023-02-06] 0xc - `export` has an optional type ascribed to it
30
// * [2023-05-10] 0xd - imports/exports drop URLs, new discriminator byte which
31
//                      allows for `(import (interface "...") ...)` syntax.
32
pub(crate) const WASM_COMPONENT_VERSION: u16 = 0xd;
33
34
const KIND_MODULE: u16 = 0x00;
35
const KIND_COMPONENT: u16 = 0x01;
36
37
/// The supported encoding formats for the parser.
38
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
39
pub enum Encoding {
40
    /// The encoding format is a WebAssembly module.
41
    Module,
42
    /// The encoding format is a WebAssembly component.
43
    Component,
44
}
45
46
#[derive(Debug, Clone, Default)]
47
struct ParserCounts {
48
    function_entries: Option<u32>,
49
    code_entries: Option<u32>,
50
    data_entries: Option<u32>,
51
    data_count: Option<u32>,
52
    #[cfg(feature = "component-model")]
53
    component_start_sections: bool,
54
}
55
56
// Section order for WebAssembly modules.
57
//
58
// Component sections are unordered and allow for duplicates,
59
// so this isn't used for components.
60
#[derive(Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug)]
61
pub(crate) enum Order {
62
    #[default]
63
    Initial,
64
    Type,
65
    Import,
66
    Function,
67
    Table,
68
    Memory,
69
    Tag,
70
    Global,
71
    Export,
72
    Start,
73
    Element,
74
    DataCount,
75
    Code,
76
    Data,
77
}
78
79
/// An incremental parser of a binary WebAssembly module or component.
80
///
81
/// This type is intended to be used to incrementally parse a WebAssembly module
82
/// or component as bytes become available for the module. This can also be used
83
/// to parse modules or components that are already entirely resident within memory.
84
///
85
/// This primary function for a parser is the [`Parser::parse`] function which
86
/// will incrementally consume input. You can also use the [`Parser::parse_all`]
87
/// function to parse a module or component that is entirely resident in memory.
88
#[derive(Debug, Clone)]
89
pub struct Parser {
90
    state: State,
91
    offset: u64,
92
    max_offset: Option<u64>,
93
    encoding: Encoding,
94
    #[cfg(feature = "features")]
95
    features: WasmFeatures,
96
    counts: ParserCounts,
97
    order: (Order, u64),
98
}
99
100
#[derive(Debug, Clone)]
101
enum State {
102
    Header { expect: Option<Encoding> },
103
    SectionStart,
104
    FunctionBody { remaining: u32, len: u32 },
105
}
106
107
/// A successful return payload from [`Parser::parse`].
108
///
109
/// On success one of two possible values can be returned, either that more data
110
/// is needed to continue parsing or a chunk of the input was parsed, indicating
111
/// how much of it was parsed.
112
#[derive(Debug)]
113
pub enum Chunk<'a> {
114
    /// This can be returned at any time and indicates that more data is needed
115
    /// to proceed with parsing. Zero bytes were consumed from the input to
116
    /// [`Parser::parse`]. The `usize` value here is a hint as to how many more
117
    /// bytes are needed to continue parsing.
118
    NeedMoreData(usize),
119
120
    /// A chunk was successfully parsed.
121
    Parsed {
122
        /// This many bytes of the `data` input to [`Parser::parse`] were
123
        /// consumed to produce `payload`.
124
        consumed: usize,
125
        /// The value that we actually parsed.
126
        payload: Payload<'a>,
127
    },
128
}
129
130
/// Values that can be parsed from a WebAssembly module or component.
131
///
132
/// This enumeration is all possible chunks of pieces that can be parsed by a
133
/// [`Parser`] from a binary WebAssembly module or component. Note that for many
134
/// sections the entire section is parsed all at once, whereas other functions,
135
/// like the code section, are parsed incrementally. This is a distinction where some
136
/// sections, like the type section, are required to be fully resident in memory
137
/// (fully downloaded) before proceeding. Other sections, like the code section,
138
/// can be processed in a streaming fashion where each function is extracted
139
/// individually so it can possibly be shipped to another thread while you wait
140
/// for more functions to get downloaded.
141
///
142
/// Note that payloads, when returned, do not indicate that the module or component
143
/// is valid. For example when you receive a `Payload::TypeSection` the type
144
/// section itself has not yet actually been parsed. The reader returned will be
145
/// able to parse it, but you'll have to actually iterate the reader to do the
146
/// full parse. Each payload returned is intended to be a *window* into the
147
/// original `data` passed to [`Parser::parse`] which can be further processed
148
/// if necessary.
149
#[non_exhaustive]
150
pub enum Payload<'a> {
151
    /// Indicates the header of a WebAssembly module or component.
152
    Version {
153
        /// The version number found in the header.
154
        num: u16,
155
        /// The encoding format being parsed.
156
        encoding: Encoding,
157
        /// The range of bytes that were parsed to consume the header of the
158
        /// module or component. Note that this range is relative to the start
159
        /// of the byte stream.
160
        range: Range<u64>,
161
    },
162
163
    /// A module type section was received and the provided reader can be
164
    /// used to parse the contents of the type section.
165
    TypeSection(TypeSectionReader<'a>),
166
    /// A module import section was received and the provided reader can be
167
    /// used to parse the contents of the import section.
168
    ImportSection(ImportSectionReader<'a>),
169
    /// A module function section was received and the provided reader can be
170
    /// used to parse the contents of the function section.
171
    FunctionSection(FunctionSectionReader<'a>),
172
    /// A module table section was received and the provided reader can be
173
    /// used to parse the contents of the table section.
174
    TableSection(TableSectionReader<'a>),
175
    /// A module memory section was received and the provided reader can be
176
    /// used to parse the contents of the memory section.
177
    MemorySection(MemorySectionReader<'a>),
178
    /// A module tag section was received, and the provided reader can be
179
    /// used to parse the contents of the tag section.
180
    TagSection(TagSectionReader<'a>),
181
    /// A module global section was received and the provided reader can be
182
    /// used to parse the contents of the global section.
183
    GlobalSection(GlobalSectionReader<'a>),
184
    /// A module export section was received, and the provided reader can be
185
    /// used to parse the contents of the export section.
186
    ExportSection(ExportSectionReader<'a>),
187
    /// A module start section was received.
188
    StartSection {
189
        /// The start function index
190
        func: u32,
191
        /// The range of bytes that specify the `func` field, specified in
192
        /// offsets relative to the start of the byte stream.
193
        range: Range<u64>,
194
    },
195
    /// A module element section was received and the provided reader can be
196
    /// used to parse the contents of the element section.
197
    ElementSection(ElementSectionReader<'a>),
198
    /// A module data count section was received.
199
    DataCountSection {
200
        /// The number of data segments.
201
        count: u32,
202
        /// The range of bytes that specify the `count` field, specified in
203
        /// offsets relative to the start of the byte stream.
204
        range: Range<u64>,
205
    },
206
    /// A module data section was received and the provided reader can be
207
    /// used to parse the contents of the data section.
208
    DataSection(DataSectionReader<'a>),
209
    /// Indicator of the start of the code section of a WebAssembly module.
210
    ///
211
    /// This entry is returned whenever the code section starts. The `count`
212
    /// field indicates how many entries are in this code section. After
213
    /// receiving this start marker you're guaranteed that the next `count`
214
    /// items will be either `CodeSectionEntry` or an error will be returned.
215
    ///
216
    /// This, unlike other sections, is intended to be used for streaming the
217
    /// contents of the code section. The code section is not required to be
218
    /// fully resident in memory when we parse it. Instead a [`Parser`] is
219
    /// capable of parsing piece-by-piece of a code section.
220
    CodeSectionStart {
221
        /// The number of functions in this section.
222
        count: u32,
223
        /// The range of bytes that represent this section, specified in
224
        /// offsets relative to the start of the byte stream.
225
        range: Range<u64>,
226
        /// The size, in bytes, of the remaining contents of this section.
227
        ///
228
        /// This can be used in combination with [`Parser::skip_section`]
229
        /// where the caller will know how many bytes to skip before feeding
230
        /// bytes into `Parser` again.
231
        size: u32,
232
    },
233
    /// An entry of the code section, a function, was parsed from a WebAssembly
234
    /// module.
235
    ///
236
    /// This entry indicates that a function was successfully received from the
237
    /// code section, and the payload here is the window into the original input
238
    /// where the function resides. Note that the function itself has not been
239
    /// parsed, it's only been outlined. You'll need to process the
240
    /// `FunctionBody` provided to test whether it parses and/or is valid.
241
    CodeSectionEntry(FunctionBody<'a>),
242
243
    /// A core module section was received and the provided parser can be
244
    /// used to parse the nested module.
245
    ///
246
    /// This variant is special in that it returns a sub-`Parser`. Upon
247
    /// receiving a `ModuleSection` it is expected that the returned
248
    /// `Parser` will be used instead of the parent `Parser` until the parse has
249
    /// finished. You'll need to feed data into the `Parser` returned until it
250
    /// returns `Payload::End`. After that you'll switch back to the parent
251
    /// parser to resume parsing the rest of the current component.
252
    ///
253
    /// Note that binaries will not be parsed correctly if you feed the data for
254
    /// a nested module into the parent [`Parser`].
255
    #[cfg(feature = "component-model")]
256
    ModuleSection {
257
        /// The parser for the nested module.
258
        parser: Parser,
259
        /// The range of bytes that represent the nested module in the
260
        /// original byte stream.
261
        ///
262
        /// Note that, to better support streaming parsing and validation, the
263
        /// validator does *not* check that this range is in bounds.
264
        unchecked_range: Range<u64>,
265
    },
266
    /// A core instance section was received and the provided parser can be
267
    /// used to parse the contents of the core instance section.
268
    ///
269
    /// Currently this section is only parsed in a component.
270
    #[cfg(feature = "component-model")]
271
    InstanceSection(InstanceSectionReader<'a>),
272
    /// A core type section was received and the provided parser can be
273
    /// used to parse the contents of the core type section.
274
    ///
275
    /// Currently this section is only parsed in a component.
276
    #[cfg(feature = "component-model")]
277
    CoreTypeSection(CoreTypeSectionReader<'a>),
278
    /// A component section from a WebAssembly component was received and the
279
    /// provided parser can be used to parse the nested component.
280
    ///
281
    /// This variant is special in that it returns a sub-`Parser`. Upon
282
    /// receiving a `ComponentSection` it is expected that the returned
283
    /// `Parser` will be used instead of the parent `Parser` until the parse has
284
    /// finished. You'll need to feed data into the `Parser` returned until it
285
    /// returns `Payload::End`. After that you'll switch back to the parent
286
    /// parser to resume parsing the rest of the current component.
287
    ///
288
    /// Note that binaries will not be parsed correctly if you feed the data for
289
    /// a nested component into the parent [`Parser`].
290
    #[cfg(feature = "component-model")]
291
    ComponentSection {
292
        /// The parser for the nested component.
293
        parser: Parser,
294
        /// The range of bytes that represent the nested component in the
295
        /// original byte stream.
296
        ///
297
        /// Note that, to better support streaming parsing and validation, the
298
        /// validator does *not* check that this range is in bounds.
299
        unchecked_range: Range<u64>,
300
    },
301
    /// A component instance section was received and the provided reader can be
302
    /// used to parse the contents of the component instance section.
303
    #[cfg(feature = "component-model")]
304
    ComponentInstanceSection(ComponentInstanceSectionReader<'a>),
305
    /// A component alias section was received and the provided reader can be
306
    /// used to parse the contents of the component alias section.
307
    #[cfg(feature = "component-model")]
308
    ComponentAliasSection(SectionLimited<'a, crate::ComponentAlias<'a>>),
309
    /// A component type section was received and the provided reader can be
310
    /// used to parse the contents of the component type section.
311
    #[cfg(feature = "component-model")]
312
    ComponentTypeSection(ComponentTypeSectionReader<'a>),
313
    /// A component canonical section was received and the provided reader can be
314
    /// used to parse the contents of the component canonical section.
315
    #[cfg(feature = "component-model")]
316
    ComponentCanonicalSection(ComponentCanonicalSectionReader<'a>),
317
    /// A component start section was received.
318
    #[cfg(feature = "component-model")]
319
    ComponentStartSection {
320
        /// The start function description.
321
        start: ComponentStartFunction,
322
        /// The range of bytes that specify the `start` field.
323
        range: Range<u64>,
324
    },
325
    /// A component import section was received and the provided reader can be
326
    /// used to parse the contents of the component import section.
327
    #[cfg(feature = "component-model")]
328
    ComponentImportSection(ComponentImportSectionReader<'a>),
329
    /// A component export section was received, and the provided reader can be
330
    /// used to parse the contents of the component export section.
331
    #[cfg(feature = "component-model")]
332
    ComponentExportSection(ComponentExportSectionReader<'a>),
333
334
    /// A module or component custom section was received.
335
    CustomSection(CustomSectionReader<'a>),
336
337
    /// An unknown section was found.
338
    ///
339
    /// This variant is returned for all unknown sections encountered. This
340
    /// likely wants to be interpreted as an error by consumers of the parser,
341
    /// but this can also be used to parse sections currently unsupported by
342
    /// the parser.
343
    UnknownSection {
344
        /// The 8-bit identifier for this section.
345
        id: u8,
346
        /// The contents of this section.
347
        contents: &'a [u8],
348
        /// The range of bytes, relative to the start of the original data
349
        /// stream, that the contents of this section reside in.
350
        range: Range<u64>,
351
    },
352
353
    /// The end of the WebAssembly module or component was reached.
354
    ///
355
    /// The value is the offset in the input byte stream where the end
356
    /// was reached.
357
    End(u64),
358
}
359
360
const CUSTOM_SECTION: u8 = 0;
361
const TYPE_SECTION: u8 = 1;
362
const IMPORT_SECTION: u8 = 2;
363
const FUNCTION_SECTION: u8 = 3;
364
const TABLE_SECTION: u8 = 4;
365
const MEMORY_SECTION: u8 = 5;
366
const GLOBAL_SECTION: u8 = 6;
367
const EXPORT_SECTION: u8 = 7;
368
const START_SECTION: u8 = 8;
369
const ELEMENT_SECTION: u8 = 9;
370
const CODE_SECTION: u8 = 10;
371
const DATA_SECTION: u8 = 11;
372
const DATA_COUNT_SECTION: u8 = 12;
373
const TAG_SECTION: u8 = 13;
374
375
#[cfg(feature = "component-model")]
376
const COMPONENT_MODULE_SECTION: u8 = 1;
377
#[cfg(feature = "component-model")]
378
const COMPONENT_CORE_INSTANCE_SECTION: u8 = 2;
379
#[cfg(feature = "component-model")]
380
const COMPONENT_CORE_TYPE_SECTION: u8 = 3;
381
#[cfg(feature = "component-model")]
382
const COMPONENT_SECTION: u8 = 4;
383
#[cfg(feature = "component-model")]
384
const COMPONENT_INSTANCE_SECTION: u8 = 5;
385
#[cfg(feature = "component-model")]
386
const COMPONENT_ALIAS_SECTION: u8 = 6;
387
#[cfg(feature = "component-model")]
388
const COMPONENT_TYPE_SECTION: u8 = 7;
389
#[cfg(feature = "component-model")]
390
const COMPONENT_CANONICAL_SECTION: u8 = 8;
391
#[cfg(feature = "component-model")]
392
const COMPONENT_START_SECTION: u8 = 9;
393
#[cfg(feature = "component-model")]
394
const COMPONENT_IMPORT_SECTION: u8 = 10;
395
#[cfg(feature = "component-model")]
396
const COMPONENT_EXPORT_SECTION: u8 = 11;
397
398
impl Parser {
399
    /// Creates a new parser.
400
    ///
401
    /// Reports errors and ranges relative to `offset` provided, where `offset`
402
    /// is some logical offset within the input stream that we're parsing.
403
121k
    pub fn new(offset: u64) -> Parser {
404
121k
        Parser {
405
121k
            state: State::Header { expect: None },
406
121k
            offset,
407
121k
            max_offset: None,
408
121k
            // Assume the encoding is a module until we know otherwise
409
121k
            encoding: Encoding::Module,
410
121k
            #[cfg(feature = "features")]
411
121k
            features: WasmFeatures::all(),
412
121k
            counts: ParserCounts::default(),
413
121k
            order: (Order::default(), offset),
414
121k
        }
415
121k
    }
416
417
    /// Tests whether `bytes` looks like a core WebAssembly module.
418
    ///
419
    /// This will inspect the first 8 bytes of `bytes` and return `true` if it
420
    /// starts with the standard core WebAssembly header.
421
0
    pub fn is_core_wasm(bytes: &[u8]) -> bool {
422
        const HEADER: [u8; 8] = [
423
            WASM_MAGIC_NUMBER[0],
424
            WASM_MAGIC_NUMBER[1],
425
            WASM_MAGIC_NUMBER[2],
426
            WASM_MAGIC_NUMBER[3],
427
            WASM_MODULE_VERSION.to_le_bytes()[0],
428
            WASM_MODULE_VERSION.to_le_bytes()[1],
429
            KIND_MODULE.to_le_bytes()[0],
430
            KIND_MODULE.to_le_bytes()[1],
431
        ];
432
0
        bytes.starts_with(&HEADER)
433
0
    }
434
435
    /// Tests whether `bytes` looks like a WebAssembly component.
436
    ///
437
    /// This will inspect the first 8 bytes of `bytes` and return `true` if it
438
    /// starts with the standard WebAssembly component header.
439
0
    pub fn is_component(bytes: &[u8]) -> bool {
440
        const HEADER: [u8; 8] = [
441
            WASM_MAGIC_NUMBER[0],
442
            WASM_MAGIC_NUMBER[1],
443
            WASM_MAGIC_NUMBER[2],
444
            WASM_MAGIC_NUMBER[3],
445
            WASM_COMPONENT_VERSION.to_le_bytes()[0],
446
            WASM_COMPONENT_VERSION.to_le_bytes()[1],
447
            KIND_COMPONENT.to_le_bytes()[0],
448
            KIND_COMPONENT.to_le_bytes()[1],
449
        ];
450
0
        bytes.starts_with(&HEADER)
451
0
    }
452
453
    /// Returns the currently active set of wasm features that this parser is
454
    /// using while parsing.
455
    ///
456
    /// The default set of features is [`WasmFeatures::all()`] for new parsers.
457
    ///
458
    /// For more information see [`BinaryReader::new`].
459
    #[cfg(feature = "features")]
460
0
    pub fn features(&self) -> WasmFeatures {
461
0
        self.features
462
0
    }
463
464
    /// Sets the wasm features active while parsing to the `features` specified.
465
    ///
466
    /// The default set of features is [`WasmFeatures::all()`] for new parsers.
467
    ///
468
    /// For more information see [`BinaryReader::new`].
469
    #[cfg(feature = "features")]
470
21.4k
    pub fn set_features(&mut self, features: WasmFeatures) {
471
21.4k
        self.features = features;
472
21.4k
    }
473
474
    /// Returns the original offset that this parser is currently at.
475
26.3k
    pub fn offset(&self) -> u64 {
476
26.3k
        self.offset
477
26.3k
    }
478
479
    /// Attempts to parse a chunk of data.
480
    ///
481
    /// This method will attempt to parse the next incremental portion of a
482
    /// WebAssembly binary. Data available for the module or component is
483
    /// provided as `data`, and the data can be incomplete if more data has yet
484
    /// to arrive. The `eof` flag indicates whether more data will ever be received.
485
    ///
486
    /// There are two ways parsing can succeed with this method:
487
    ///
488
    /// * `Chunk::NeedMoreData` - this indicates that there is not enough bytes
489
    ///   in `data` to parse a payload. The caller needs to wait for more data to
490
    ///   be available in this situation before calling this method again. It is
491
    ///   guaranteed that this is only returned if `eof` is `false`.
492
    ///
493
    /// * `Chunk::Parsed` - this indicates that a chunk of the input was
494
    ///   successfully parsed. The payload is available in this variant of what
495
    ///   was parsed, and this also indicates how many bytes of `data` was
496
    ///   consumed. It's expected that the caller will not provide these bytes
497
    ///   back to the [`Parser`] again.
498
    ///
499
    /// Note that all `Chunk` return values are connected, with a lifetime, to
500
    /// the input buffer. Each parsed chunk borrows the input buffer and is a
501
    /// view into it for successfully parsed chunks.
502
    ///
503
    /// It is expected that you'll call this method until `Payload::End` is
504
    /// reached, at which point you're guaranteed that the parse has completed.
505
    /// Note that complete parsing, for the top-level module or component,
506
    /// implies that `data` is empty and `eof` is `true`.
507
    ///
508
    /// # Errors
509
    ///
510
    /// Parse errors are returned as an `Err`. Errors can happen when the
511
    /// structure of the data is unexpected or if sections are too large for
512
    /// example. Note that errors are not returned for malformed *contents* of
513
    /// sections here. Sections are generally not individually parsed and each
514
    /// returned [`Payload`] needs to be iterated over further to detect all
515
    /// errors.
516
    ///
517
    /// # Examples
518
    ///
519
    /// An example of reading a wasm file from a stream (`std::io::Read`) and
520
    /// incrementally parsing it.
521
    ///
522
    /// ```
523
    /// use std::io::Read;
524
    /// use anyhow::Result;
525
    /// use wasmparser::{Parser, Chunk, Payload::*};
526
    ///
527
    /// fn parse(mut reader: impl Read) -> Result<()> {
528
    ///     let mut buf = Vec::new();
529
    ///     let mut cur = Parser::new(0);
530
    ///     let mut eof = false;
531
    ///     let mut stack = Vec::new();
532
    ///
533
    ///     loop {
534
    ///         let (payload, consumed) = match cur.parse(&buf, eof)? {
535
    ///             Chunk::NeedMoreData(hint) => {
536
    ///                 assert!(!eof); // otherwise an error would be returned
537
    ///
538
    ///                 // Use the hint to preallocate more space, then read
539
    ///                 // some more data into our buffer.
540
    ///                 //
541
    ///                 // Note that the buffer management here is not ideal,
542
    ///                 // but it's compact enough to fit in an example!
543
    ///                 let len = buf.len();
544
    ///                 buf.extend((0..hint).map(|_| 0u8));
545
    ///                 let n = reader.read(&mut buf[len..])?;
546
    ///                 buf.truncate(len + n);
547
    ///                 eof = n == 0;
548
    ///                 continue;
549
    ///             }
550
    ///
551
    ///             Chunk::Parsed { consumed, payload } => (payload, consumed),
552
    ///         };
553
    ///
554
    ///         match payload {
555
    ///             // Sections for WebAssembly modules
556
    ///             Version { .. } => { /* ... */ }
557
    ///             TypeSection(_) => { /* ... */ }
558
    ///             ImportSection(_) => { /* ... */ }
559
    ///             FunctionSection(_) => { /* ... */ }
560
    ///             TableSection(_) => { /* ... */ }
561
    ///             MemorySection(_) => { /* ... */ }
562
    ///             TagSection(_) => { /* ... */ }
563
    ///             GlobalSection(_) => { /* ... */ }
564
    ///             ExportSection(_) => { /* ... */ }
565
    ///             StartSection { .. } => { /* ... */ }
566
    ///             ElementSection(_) => { /* ... */ }
567
    ///             DataCountSection { .. } => { /* ... */ }
568
    ///             DataSection(_) => { /* ... */ }
569
    ///
570
    ///             // Here we know how many functions we'll be receiving as
571
    ///             // `CodeSectionEntry`, so we can prepare for that, and
572
    ///             // afterwards we can parse and handle each function
573
    ///             // individually.
574
    ///             CodeSectionStart { .. } => { /* ... */ }
575
    ///             CodeSectionEntry(body) => {
576
    ///                 // here we can iterate over `body` to parse the function
577
    ///                 // and its locals
578
    ///             }
579
    ///
580
    ///             // Sections for WebAssembly components
581
    ///             InstanceSection(_) => { /* ... */ }
582
    ///             CoreTypeSection(_) => { /* ... */ }
583
    ///             ComponentInstanceSection(_) => { /* ... */ }
584
    ///             ComponentAliasSection(_) => { /* ... */ }
585
    ///             ComponentTypeSection(_) => { /* ... */ }
586
    ///             ComponentCanonicalSection(_) => { /* ... */ }
587
    ///             ComponentStartSection { .. } => { /* ... */ }
588
    ///             ComponentImportSection(_) => { /* ... */ }
589
    ///             ComponentExportSection(_) => { /* ... */ }
590
    ///
591
    ///             ModuleSection { parser, .. }
592
    ///             | ComponentSection { parser, .. } => {
593
    ///                 stack.push(cur.clone());
594
    ///                 cur = parser.clone();
595
    ///             }
596
    ///
597
    ///             CustomSection(_) => { /* ... */ }
598
    ///
599
    ///             // Once we've reached the end of a parser we either resume
600
    ///             // at the parent parser or we break out of the loop because
601
    ///             // we're done.
602
    ///             End(_) => {
603
    ///                 if let Some(parent_parser) = stack.pop() {
604
    ///                     cur = parent_parser;
605
    ///                 } else {
606
    ///                     break;
607
    ///                 }
608
    ///             }
609
    ///
610
    ///             // most likely you'd return an error here
611
    ///             _ => { /* ... */ }
612
    ///         }
613
    ///
614
    ///         // once we're done processing the payload we can forget the
615
    ///         // original.
616
    ///         buf.drain(..consumed);
617
    ///     }
618
    ///
619
    ///     Ok(())
620
    /// }
621
    ///
622
    /// # parse(&b"\0asm\x01\0\0\0"[..]).unwrap();
623
    /// ```
624
3.45M
    pub fn parse<'a>(&mut self, data: &'a [u8], eof: bool) -> Result<Chunk<'a>> {
625
3.45M
        let max_offset = self.max_offset.unwrap_or(u64::MAX);
626
3.45M
        debug_assert!(self.offset <= max_offset, "inverted offset range");
627
3.45M
        let max_len = offsets::max_data_len(self.offset, max_offset);
628
3.45M
        let (data, eof) = if max_len < data.len() {
629
182k
            if self.max_offset.is_none() {
630
0
                return Err(offsets::err_too_many_bytes(
631
0
                    self.offset,
632
0
                    data.len(),
633
0
                    max_len,
634
0
                ));
635
182k
            }
636
182k
            (&data[..max_len], true)
637
        } else {
638
3.27M
            (data, eof)
639
        };
640
3.45M
        let mut reader = BinaryReader::new(data, self.offset);
641
        #[cfg(feature = "features")]
642
3.45M
        {
643
3.45M
            reader.set_features(self.features);
644
3.45M
        }
645
3.45M
        match self.parse_reader(&mut reader, eof) {
646
1.88M
            Ok(payload) => {
647
                // Be sure to update our offset with how far we got in the reader
648
1.88M
                let consumed = reader.current_position();
649
1.88M
                self.offset += consumed as u64;
650
1.88M
                Ok(Chunk::Parsed {
651
1.88M
                    consumed: consumed,
652
1.88M
                    payload,
653
1.88M
                })
654
            }
655
1.57M
            Err(e) => {
656
                // If we're at EOF then there's no way we can recover from any
657
                // error, so continue to propagate it.
658
1.57M
                if eof {
659
128
                    return Err(e);
660
1.57M
                }
661
662
                // If our error doesn't look like it can be resolved with more
663
                // data being pulled down, then propagate it, otherwise switch
664
                // the error to "feed me please"
665
1.57M
                match e.needed_hint() {
666
1.57M
                    Some(hint) => Ok(Chunk::NeedMoreData(hint)),
667
32
                    None => Err(e),
668
                }
669
            }
670
        }
671
3.45M
    }
672
673
490k
    fn update_order(&mut self, order: Order, pos: u64) -> Result<()> {
674
490k
        if self.encoding == Encoding::Module {
675
490k
            match self.order {
676
490k
                (last_order, last_pos) if last_order >= order && last_pos < pos => {
677
0
                    bail!(pos, "section out of order")
678
                }
679
490k
                _ => (),
680
            }
681
0
        }
682
683
490k
        self.order = (order, pos);
684
685
490k
        Ok(())
686
490k
    }
687
688
3.50M
    fn parse_reader<'a>(
689
3.50M
        &mut self,
690
3.50M
        reader: &mut BinaryReader<'a>,
691
3.50M
        eof: bool,
692
3.50M
    ) -> Result<Payload<'a>> {
693
        use Payload::*;
694
695
3.50M
        match self.state {
696
205k
            State::Header { expect } => {
697
205k
                let start = reader.original_position();
698
205k
                let header_version = reader.read_header_version()?;
699
121k
                let num = header_version as u16;
700
121k
                self.encoding = match (num, (header_version >> 16) as u16) {
701
29.3k
                    (WASM_MODULE_VERSION, KIND_MODULE) => match expect {
702
73.1k
                        None | Some(Encoding::Module) => Encoding::Module,
703
                        Some(Encoding::Component) => {
704
0
                            bail!(start, "expected a version header for a component")
705
                        }
706
                    },
707
11.3k
                    (WASM_COMPONENT_VERSION, KIND_COMPONENT) => match expect {
708
48.1k
                        None | Some(Encoding::Component) => Encoding::Component,
709
                        Some(Encoding::Module) => {
710
0
                            bail!(start, "expected a version header for a module")
711
                        }
712
                    },
713
2
                    _ => bail!(start + 4, "unknown binary version: {header_version:#10x}"),
714
                };
715
121k
                self.state = State::SectionStart;
716
121k
                Ok(Version {
717
121k
                    num,
718
121k
                    encoding: self.encoding,
719
121k
                    range: start..reader.original_position(),
720
121k
                })
721
            }
722
            State::SectionStart => {
723
                // If we're at eof and there are no bytes in our buffer, then
724
                // that means we reached the end of the data since it's
725
                // just a bunch of sections concatenated after the header.
726
2.55M
                if eof && reader.bytes_remaining() == 0 {
727
123k
                    self.check_function_code_counts(reader.original_position())?;
728
123k
                    self.check_data_count(reader.original_position())?;
729
123k
                    return Ok(Payload::End(reader.original_position()));
730
2.43M
                }
731
732
                // Corrupted binaries containing multiple modules or
733
                // components will fail because a section can never start with
734
                // the magic number: 0 is custom section, 'a' is section len
735
                // of 97, `s` is section name string len of 115, at which
736
                // point validation will fail because name string is bigger
737
                // than section. Report a better error instead:
738
2.43M
                match reader.peek_bytes(4) {
739
988k
                    Ok(peek) if peek == WASM_MAGIC_NUMBER => {
740
0
                        return Err(Error::new(
741
0
                            "expected section, got wasm magic number",
742
0
                            reader.original_position(),
743
0
                        ));
744
                    }
745
2.43M
                    _ => {}
746
                }
747
748
2.43M
                let id_pos = reader.original_position();
749
2.43M
                let id = reader.read_u8()?;
750
1.95M
                if id & 0x80 != 0 {
751
0
                    return Err(Error::new("malformed section id", id_pos));
752
1.95M
                }
753
1.95M
                let len_pos = reader.original_position();
754
1.95M
                let mut len = reader.read_var_u32()?;
755
756
                // Test to make sure that this section actually fits within
757
                // `Parser::max_size`. This doesn't matter for top-level modules
758
                // but it is required for nested modules/components to correctly ensure
759
                // that all sections live entirely within their section of the
760
                // file.
761
1.46M
                let section_start = reader.original_position();
762
1.46M
                let max_offset = self.max_offset.unwrap_or(u64::MAX);
763
1.46M
                let Some(section_end) = section_start
764
1.46M
                    .checked_add(u64::from(len))
765
1.46M
                    .and_then(|section_end| (section_end <= max_offset).then_some(section_end))
766
                else {
767
0
                    return Err(Error::new(
768
0
                        &format!("section too large, {len} goes past 0x{max_offset:x}"),
769
0
                        len_pos,
770
0
                    ));
771
                };
772
773
1.46M
                match (self.encoding, id) {
774
                    // Custom sections for both modules and components.
775
165k
                    (_, 0) => section(reader, len, CustomSectionReader::new, CustomSection),
776
777
                    // Module sections
778
                    (Encoding::Module, TYPE_SECTION) => {
779
95.3k
                        self.update_order(Order::Type, section_start)?;
780
95.3k
                        section(reader, len, TypeSectionReader::new, TypeSection)
781
                    }
782
                    (Encoding::Module, IMPORT_SECTION) => {
783
54.8k
                        self.update_order(Order::Import, section_start)?;
784
54.8k
                        section(reader, len, ImportSectionReader::new, ImportSection)
785
                    }
786
                    (Encoding::Module, FUNCTION_SECTION) => {
787
67.8k
                        self.update_order(Order::Function, section_start)?;
788
67.8k
                        let s = section(reader, len, FunctionSectionReader::new, FunctionSection)?;
789
56.3k
                        match &s {
790
56.3k
                            FunctionSection(f) => self.counts.function_entries = Some(f.count()),
791
0
                            _ => unreachable!(),
792
                        }
793
56.3k
                        Ok(s)
794
                    }
795
                    (Encoding::Module, TABLE_SECTION) => {
796
15.5k
                        self.update_order(Order::Table, section_start)?;
797
15.5k
                        section(reader, len, TableSectionReader::new, TableSection)
798
                    }
799
                    (Encoding::Module, MEMORY_SECTION) => {
800
53.4k
                        self.update_order(Order::Memory, section_start)?;
801
53.4k
                        section(reader, len, MemorySectionReader::new, MemorySection)
802
                    }
803
                    (Encoding::Module, GLOBAL_SECTION) => {
804
23.3k
                        self.update_order(Order::Global, section_start)?;
805
23.3k
                        section(reader, len, GlobalSectionReader::new, GlobalSection)
806
                    }
807
                    (Encoding::Module, EXPORT_SECTION) => {
808
57.5k
                        self.update_order(Order::Export, section_start)?;
809
57.5k
                        section(reader, len, ExportSectionReader::new, ExportSection)
810
                    }
811
                    (Encoding::Module, START_SECTION) => {
812
23.8k
                        self.update_order(Order::Start, section_start)?;
813
23.8k
                        let (func, range) = single_item(reader, section_end, "start")?;
814
15.1k
                        Ok(StartSection { func, range })
815
                    }
816
                    (Encoding::Module, ELEMENT_SECTION) => {
817
13.3k
                        self.update_order(Order::Element, section_start)?;
818
13.3k
                        section(reader, len, ElementSectionReader::new, ElementSection)
819
                    }
820
                    (Encoding::Module, CODE_SECTION) => {
821
67.7k
                        self.update_order(Order::Code, section_start)?;
822
67.7k
                        let count = delimited(reader, &mut len, |r| r.read_var_u32())?;
823
56.2k
                        self.counts.code_entries = Some(count);
824
56.2k
                        self.check_function_code_counts(section_start)?;
825
56.2k
                        let range = section_start..section_end;
826
56.2k
                        self.state = State::FunctionBody {
827
56.2k
                            remaining: count,
828
56.2k
                            len,
829
56.2k
                        };
830
56.2k
                        Ok(CodeSectionStart {
831
56.2k
                            count,
832
56.2k
                            range,
833
56.2k
                            size: len,
834
56.2k
                        })
835
                    }
836
                    (Encoding::Module, DATA_SECTION) => {
837
8.59k
                        self.update_order(Order::Data, section_start)?;
838
8.59k
                        let s = section(reader, len, DataSectionReader::new, DataSection)?;
839
8.59k
                        match &s {
840
8.59k
                            DataSection(d) => self.counts.data_entries = Some(d.count()),
841
0
                            _ => unreachable!(),
842
                        }
843
8.59k
                        self.check_data_count(reader.original_position())?;
844
8.59k
                        Ok(s)
845
                    }
846
                    (Encoding::Module, DATA_COUNT_SECTION) => {
847
6.01k
                        self.update_order(Order::DataCount, section_start)?;
848
6.01k
                        let (count, range) = single_item(reader, section_end, "data count")?;
849
6.01k
                        self.counts.data_count = Some(count);
850
6.01k
                        Ok(DataCountSection { count, range })
851
                    }
852
                    (Encoding::Module, TAG_SECTION) => {
853
3.10k
                        self.update_order(Order::Tag, section_start)?;
854
3.10k
                        section(reader, len, TagSectionReader::new, TagSection)
855
                    }
856
857
                    // Component sections
858
                    #[cfg(feature = "component-model")]
859
                    (Encoding::Component, COMPONENT_MODULE_SECTION)
860
                    | (Encoding::Component, COMPONENT_SECTION) => {
861
40.7k
                        if len > MAX_WASM_MODULE_SIZE {
862
0
                            bail!(
863
0
                                len_pos,
864
                                "{} section is too large",
865
0
                                if id == COMPONENT_MODULE_SECTION {
866
0
                                    "module"
867
                                } else {
868
0
                                    "component"
869
                                }
870
                            );
871
40.7k
                        }
872
873
40.7k
                        let range = section_start..section_end;
874
                        // Do no consume these bytes from the reader. The parse function will
875
                        // additionally bump this by the consumed amount, which will land us
876
                        // at section_end.
877
40.7k
                        self.offset += u64::from(len);
878
40.7k
                        let mut parser = Parser::new(section_start);
879
                        parser.state = State::Header {
880
40.7k
                            expect: Some(if id == COMPONENT_MODULE_SECTION {
881
29.3k
                                Encoding::Module
882
                            } else {
883
11.3k
                                Encoding::Component
884
                            }),
885
                        };
886
                        #[cfg(feature = "features")]
887
40.7k
                        {
888
40.7k
                            parser.features = self.features;
889
40.7k
                        }
890
40.7k
                        parser.max_offset = Some(section_end);
891
892
40.7k
                        Ok(match id {
893
29.3k
                            COMPONENT_MODULE_SECTION => ModuleSection {
894
29.3k
                                parser,
895
29.3k
                                unchecked_range: range,
896
29.3k
                            },
897
11.3k
                            COMPONENT_SECTION => ComponentSection {
898
11.3k
                                parser,
899
11.3k
                                unchecked_range: range,
900
11.3k
                            },
901
0
                            _ => unreachable!(),
902
                        })
903
                    }
904
                    #[cfg(feature = "component-model")]
905
                    (Encoding::Component, COMPONENT_CORE_INSTANCE_SECTION) => {
906
56.2k
                        section(reader, len, InstanceSectionReader::new, InstanceSection)
907
                    }
908
                    #[cfg(feature = "component-model")]
909
                    (Encoding::Component, COMPONENT_CORE_TYPE_SECTION) => {
910
0
                        section(reader, len, CoreTypeSectionReader::new, CoreTypeSection)
911
                    }
912
                    #[cfg(feature = "component-model")]
913
18.9k
                    (Encoding::Component, COMPONENT_INSTANCE_SECTION) => section(
914
18.9k
                        reader,
915
18.9k
                        len,
916
18.9k
                        ComponentInstanceSectionReader::new,
917
18.9k
                        ComponentInstanceSection,
918
                    ),
919
                    #[cfg(feature = "component-model")]
920
                    (Encoding::Component, COMPONENT_ALIAS_SECTION) => {
921
72.5k
                        section(reader, len, SectionLimited::new, ComponentAliasSection)
922
                    }
923
                    #[cfg(feature = "component-model")]
924
276k
                    (Encoding::Component, COMPONENT_TYPE_SECTION) => section(
925
276k
                        reader,
926
276k
                        len,
927
276k
                        ComponentTypeSectionReader::new,
928
276k
                        ComponentTypeSection,
929
                    ),
930
                    #[cfg(feature = "component-model")]
931
60.3k
                    (Encoding::Component, COMPONENT_CANONICAL_SECTION) => section(
932
60.3k
                        reader,
933
60.3k
                        len,
934
60.3k
                        ComponentCanonicalSectionReader::new,
935
60.3k
                        ComponentCanonicalSection,
936
                    ),
937
                    #[cfg(feature = "component-model")]
938
                    (Encoding::Component, COMPONENT_START_SECTION) => {
939
0
                        match self.counts.component_start_sections {
940
0
                            false => self.counts.component_start_sections = true,
941
                            true => {
942
0
                                bail!(
943
0
                                    reader.original_position(),
944
                                    "component cannot have more than one start function"
945
                                )
946
                            }
947
                        }
948
0
                        let (start, range) = single_item(reader, section_end, "component start")?;
949
0
                        Ok(ComponentStartSection { start, range })
950
                    }
951
                    #[cfg(feature = "component-model")]
952
42.3k
                    (Encoding::Component, COMPONENT_IMPORT_SECTION) => section(
953
42.3k
                        reader,
954
42.3k
                        len,
955
42.3k
                        ComponentImportSectionReader::new,
956
42.3k
                        ComponentImportSection,
957
                    ),
958
                    #[cfg(feature = "component-model")]
959
240k
                    (Encoding::Component, COMPONENT_EXPORT_SECTION) => section(
960
240k
                        reader,
961
240k
                        len,
962
240k
                        ComponentExportSectionReader::new,
963
240k
                        ComponentExportSection,
964
                    ),
965
0
                    (_, id) => {
966
0
                        let offset = reader.original_position();
967
0
                        let contents = reader.read_bytes(len as usize)?;
968
0
                        let range = offset..section_end;
969
0
                        Ok(UnknownSection {
970
0
                            id,
971
0
                            contents,
972
0
                            range,
973
0
                        })
974
                    }
975
                }
976
            }
977
978
            // Once we hit 0 remaining incrementally parsed items, with 0
979
            // remaining bytes in each section, we're done and can switch back
980
            // to parsing sections.
981
            State::FunctionBody {
982
                remaining: 0,
983
                len: 0,
984
            } => {
985
50.4k
                self.state = State::SectionStart;
986
50.4k
                self.parse_reader(reader, eof)
987
            }
988
989
            // ... otherwise trailing bytes with no remaining entries in these
990
            // sections indicates an error.
991
0
            State::FunctionBody { remaining: 0, len } => {
992
0
                debug_assert!(len > 0);
993
0
                let offset = reader.original_position();
994
0
                Err(Error::new("trailing bytes at end of section", offset))
995
            }
996
997
            // Functions are relatively easy to parse when we know there's at
998
            // least one remaining and at least one byte available to read
999
            // things.
1000
            //
1001
            // We use the remaining length try to read a u32 size of the
1002
            // function, and using that size we require the entire function be
1003
            // resident in memory. This means that we're reading whole chunks of
1004
            // functions at a time.
1005
            //
1006
            // Limiting via `Parser::max_size` (nested parsing) happens above in
1007
            // `fn parse`, and limiting by our section size happens via
1008
            // `delimited`. Actual parsing of the function body is delegated to
1009
            // the caller to iterate over the `FunctionBody` structure.
1010
698k
            State::FunctionBody { remaining, mut len } => {
1011
698k
                let body = delimited(reader, &mut len, |r| {
1012
698k
                    Ok(FunctionBody::new(r.read_reader()?))
1013
698k
                })?;
1014
601k
                self.state = State::FunctionBody {
1015
601k
                    remaining: remaining - 1,
1016
601k
                    len,
1017
601k
                };
1018
601k
                Ok(CodeSectionEntry(body))
1019
            }
1020
        }
1021
3.50M
    }
1022
1023
    /// Convenience function that can be used to parse a module or component
1024
    /// that is entirely resident in memory.
1025
    ///
1026
    /// This function will parse the `data` provided as a WebAssembly module
1027
    /// or component.
1028
    ///
1029
    /// Note that when this function yields sections that provide parsers,
1030
    /// no further action is required for those sections as payloads from
1031
    /// those parsers will be automatically returned.
1032
    ///
1033
    /// # Examples
1034
    ///
1035
    /// An example of reading a wasm file from a stream (`std::io::Read`) into
1036
    /// a buffer and then parsing it.
1037
    ///
1038
    /// ```
1039
    /// use std::io::Read;
1040
    /// use anyhow::Result;
1041
    /// use wasmparser::{Parser, Chunk, Payload::*};
1042
    ///
1043
    /// fn parse(mut reader: impl Read) -> Result<()> {
1044
    ///     let mut buf = Vec::new();
1045
    ///     reader.read_to_end(&mut buf)?;
1046
    ///     let parser = Parser::new(0);
1047
    ///
1048
    ///     for payload in parser.parse_all(&buf) {
1049
    ///         match payload? {
1050
    ///             // Sections for WebAssembly modules
1051
    ///             Version { .. } => { /* ... */ }
1052
    ///             TypeSection(_) => { /* ... */ }
1053
    ///             ImportSection(_) => { /* ... */ }
1054
    ///             FunctionSection(_) => { /* ... */ }
1055
    ///             TableSection(_) => { /* ... */ }
1056
    ///             MemorySection(_) => { /* ... */ }
1057
    ///             TagSection(_) => { /* ... */ }
1058
    ///             GlobalSection(_) => { /* ... */ }
1059
    ///             ExportSection(_) => { /* ... */ }
1060
    ///             StartSection { .. } => { /* ... */ }
1061
    ///             ElementSection(_) => { /* ... */ }
1062
    ///             DataCountSection { .. } => { /* ... */ }
1063
    ///             DataSection(_) => { /* ... */ }
1064
    ///
1065
    ///             // Here we know how many functions we'll be receiving as
1066
    ///             // `CodeSectionEntry`, so we can prepare for that, and
1067
    ///             // afterwards we can parse and handle each function
1068
    ///             // individually.
1069
    ///             CodeSectionStart { .. } => { /* ... */ }
1070
    ///             CodeSectionEntry(body) => {
1071
    ///                 // here we can iterate over `body` to parse the function
1072
    ///                 // and its locals
1073
    ///             }
1074
    ///
1075
    ///             // Sections for WebAssembly components
1076
    ///             ModuleSection { .. } => { /* ... */ }
1077
    ///             InstanceSection(_) => { /* ... */ }
1078
    ///             CoreTypeSection(_) => { /* ... */ }
1079
    ///             ComponentSection { .. } => { /* ... */ }
1080
    ///             ComponentInstanceSection(_) => { /* ... */ }
1081
    ///             ComponentAliasSection(_) => { /* ... */ }
1082
    ///             ComponentTypeSection(_) => { /* ... */ }
1083
    ///             ComponentCanonicalSection(_) => { /* ... */ }
1084
    ///             ComponentStartSection { .. } => { /* ... */ }
1085
    ///             ComponentImportSection(_) => { /* ... */ }
1086
    ///             ComponentExportSection(_) => { /* ... */ }
1087
    ///
1088
    ///             CustomSection(_) => { /* ... */ }
1089
    ///
1090
    ///             // Once we've reached the end of a parser we either resume
1091
    ///             // at the parent parser or the payload iterator is at its
1092
    ///             // end and we're done.
1093
    ///             End(_) => {}
1094
    ///
1095
    ///             // most likely you'd return an error here, but if you want
1096
    ///             // you can also inspect the raw contents of unknown sections
1097
    ///             other => {
1098
    ///                 match other.as_section() {
1099
    ///                     Some((id, range)) => { /* ... */ }
1100
    ///                     None => { /* ... */ }
1101
    ///                 }
1102
    ///             }
1103
    ///         }
1104
    ///     }
1105
    ///
1106
    ///     Ok(())
1107
    /// }
1108
    ///
1109
    /// # parse(&b"\0asm\x01\0\0\0"[..]).unwrap();
1110
    /// ```
1111
55.4k
    pub fn parse_all(self, mut data: &[u8]) -> impl Iterator<Item = Result<Payload<'_>>> {
1112
55.4k
        let mut stack = Vec::new();
1113
55.4k
        let mut cur = self;
1114
55.4k
        let mut done = false;
1115
1.10M
        iter::from_fn(move || {
1116
1.10M
            if done {
1117
42.1k
                return None;
1118
1.06M
            }
1119
1.06M
            let payload = match cur.parse(data, true) {
1120
                // Propagate all errors
1121
77
                Err(e) => {
1122
77
                    done = true;
1123
77
                    return Some(Err(e));
1124
                }
1125
1126
                // This isn't possible because `eof` is always true.
1127
0
                Ok(Chunk::NeedMoreData(_)) => unreachable!(),
1128
1129
1.06M
                Ok(Chunk::Parsed { payload, consumed }) => {
1130
1.06M
                    data = &data[consumed..];
1131
1.06M
                    payload
1132
                }
1133
            };
1134
1135
1.06M
            match &payload {
1136
                #[cfg(feature = "component-model")]
1137
9.78k
                Payload::ModuleSection { parser, .. }
1138
13.5k
                | Payload::ComponentSection { parser, .. } => {
1139
13.5k
                    stack.push(cur.clone());
1140
13.5k
                    cur = parser.clone();
1141
13.5k
                }
1142
64.5k
                Payload::End(_) => match stack.pop() {
1143
13.5k
                    Some(p) => cur = p,
1144
50.9k
                    None => done = true,
1145
                },
1146
1147
988k
                _ => {}
1148
            }
1149
1150
1.06M
            Some(Ok(payload))
1151
1.10M
        })
1152
55.4k
    }
1153
1154
    /// Skip parsing the code section entirely.
1155
    ///
1156
    /// This function can be used to indicate, after receiving
1157
    /// `CodeSectionStart`, that the section will not be parsed.
1158
    ///
1159
    /// The caller will be responsible for skipping `size` bytes (found in the
1160
    /// `CodeSectionStart` payload). Bytes should only be fed into `parse`
1161
    /// after the `size` bytes have been skipped.
1162
    ///
1163
    /// # Panics
1164
    ///
1165
    /// This function will panic if the parser is not in a state where it's
1166
    /// parsing the code section.
1167
    ///
1168
    /// # Examples
1169
    ///
1170
    /// ```
1171
    /// use wasmparser::{Result, Parser, Chunk, Payload::*};
1172
    /// use core::ops::Range;
1173
    ///
1174
    /// fn objdump_headers(mut wasm: &[u8]) -> Result<()> {
1175
    ///     let mut parser = Parser::new(0);
1176
    ///     loop {
1177
    ///         let payload = match parser.parse(wasm, true)? {
1178
    ///             Chunk::Parsed { consumed, payload } => {
1179
    ///                 wasm = &wasm[consumed..];
1180
    ///                 payload
1181
    ///             }
1182
    ///             // this state isn't possible with `eof = true`
1183
    ///             Chunk::NeedMoreData(_) => unreachable!(),
1184
    ///         };
1185
    ///         match payload {
1186
    ///             TypeSection(s) => print_range("type section", &s.range()),
1187
    ///             ImportSection(s) => print_range("import section", &s.range()),
1188
    ///             // .. other sections
1189
    ///
1190
    ///             // Print the range of the code section we see, but don't
1191
    ///             // actually iterate over each individual function.
1192
    ///             CodeSectionStart { range, size, .. } => {
1193
    ///                 print_range("code section", &range);
1194
    ///                 parser.skip_section();
1195
    ///                 wasm = &wasm[size as usize..];
1196
    ///             }
1197
    ///             End(_) => break,
1198
    ///             _ => {}
1199
    ///         }
1200
    ///     }
1201
    ///     Ok(())
1202
    /// }
1203
    ///
1204
    /// fn print_range(section: &str, range: &Range<u64>) {
1205
    ///     println!("{:>40}: {:#010x} - {:#010x}", section, range.start, range.end);
1206
    /// }
1207
    /// ```
1208
5.69k
    pub fn skip_section(&mut self) {
1209
5.69k
        let skip = match self.state {
1210
5.69k
            State::FunctionBody { remaining: _, len } => len,
1211
0
            _ => panic!("wrong state to call `skip_section`"),
1212
        };
1213
5.69k
        self.offset += u64::from(skip);
1214
5.69k
        self.state = State::SectionStart;
1215
5.69k
    }
1216
1217
179k
    fn check_function_code_counts(&self, pos: u64) -> Result<()> {
1218
179k
        match (self.counts.function_entries, self.counts.code_entries) {
1219
112k
            (Some(n), Some(m)) if n != m => {
1220
0
                bail!(pos, "function and code section have inconsistent lengths")
1221
            }
1222
0
            (Some(n), None) if n > 0 => bail!(
1223
0
                pos,
1224
                "function section has non-zero count but code section is absent"
1225
            ),
1226
0
            (None, Some(m)) if m > 0 => bail!(
1227
0
                pos,
1228
                "function section is absent but code section has non-zero count"
1229
            ),
1230
179k
            _ => Ok(()),
1231
        }
1232
179k
    }
1233
1234
131k
    fn check_data_count(&self, pos: u64) -> Result<()> {
1235
131k
        match (self.counts.data_count, self.counts.data_entries) {
1236
11.9k
            (Some(n), Some(m)) if n != m => {
1237
0
                bail!(pos, "data count and data section have inconsistent lengths")
1238
            }
1239
0
            (Some(n), None) if n > 0 => {
1240
0
                bail!(pos, "data count is non-zero but data section is absent")
1241
            }
1242
131k
            _ => Ok(()),
1243
        }
1244
131k
    }
1245
}
1246
1247
/// Parses an entire section resident in memory into a `Payload`.
1248
///
1249
/// Requires that `len` bytes are resident in `reader` and uses `ctor`/`variant`
1250
/// to construct the section to return.
1251
1.32M
fn section<'a, T>(
1252
1.32M
    reader: &mut BinaryReader<'a>,
1253
1.32M
    len: u32,
1254
1.32M
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
1.32M
    variant: fn(T) -> Payload<'a>,
1256
1.32M
) -> Result<Payload<'a>> {
1257
1.32M
    let reader = reader.skip(|r| {
1258
1.32M
        r.read_bytes(len as usize)?;
1259
918k
        Ok(())
1260
1.32M
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::data::Data>>::{closure#0}
Line
Count
Source
1257
8.59k
    let reader = reader.skip(|r| {
1258
8.59k
        r.read_bytes(len as usize)?;
1259
8.59k
        Ok(())
1260
8.59k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::types::MemoryType>>::{closure#0}
Line
Count
Source
1257
53.4k
    let reader = reader.skip(|r| {
1258
53.4k
        r.read_bytes(len as usize)?;
1259
44.6k
        Ok(())
1260
53.4k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::types::TagType>>::{closure#0}
Line
Count
Source
1257
3.10k
    let reader = reader.skip(|r| {
1258
3.10k
        r.read_bytes(len as usize)?;
1259
3.10k
        Ok(())
1260
3.10k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::types::RecGroup>>::{closure#0}
Line
Count
Source
1257
95.3k
    let reader = reader.skip(|r| {
1258
95.3k
        r.read_bytes(len as usize)?;
1259
75.7k
        Ok(())
1260
95.3k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::tables::Table>>::{closure#0}
Line
Count
Source
1257
15.5k
    let reader = reader.skip(|r| {
1258
15.5k
        r.read_bytes(len as usize)?;
1259
14.2k
        Ok(())
1260
15.5k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::exports::Export>>::{closure#0}
Line
Count
Source
1257
57.5k
    let reader = reader.skip(|r| {
1258
57.5k
        r.read_bytes(len as usize)?;
1259
46.7k
        Ok(())
1260
57.5k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::globals::Global>>::{closure#0}
Line
Count
Source
1257
23.3k
    let reader = reader.skip(|r| {
1258
23.3k
        r.read_bytes(len as usize)?;
1259
22.6k
        Ok(())
1260
23.3k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::imports::Imports>>::{closure#0}
Line
Count
Source
1257
54.8k
    let reader = reader.skip(|r| {
1258
54.8k
        r.read_bytes(len as usize)?;
1259
42.7k
        Ok(())
1260
54.8k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::elements::Element>>::{closure#0}
Line
Count
Source
1257
13.3k
    let reader = reader.skip(|r| {
1258
13.3k
        r.read_bytes(len as usize)?;
1259
11.3k
        Ok(())
1260
13.3k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::canonicals::CanonicalFunction>>::{closure#0}
Line
Count
Source
1257
60.3k
    let reader = reader.skip(|r| {
1258
60.3k
        r.read_bytes(len as usize)?;
1259
36.2k
        Ok(())
1260
60.3k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::types::ComponentType>>::{closure#0}
Line
Count
Source
1257
276k
    let reader = reader.skip(|r| {
1258
276k
        r.read_bytes(len as usize)?;
1259
174k
        Ok(())
1260
276k
    })?;
Unexecuted instantiation: wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::types::CoreType>>::{closure#0}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::aliases::ComponentAlias>>::{closure#0}
Line
Count
Source
1257
72.5k
    let reader = reader.skip(|r| {
1258
72.5k
        r.read_bytes(len as usize)?;
1259
43.5k
        Ok(())
1260
72.5k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::exports::ComponentExport>>::{closure#0}
Line
Count
Source
1257
240k
    let reader = reader.skip(|r| {
1258
240k
        r.read_bytes(len as usize)?;
1259
152k
        Ok(())
1260
240k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::imports::ComponentImport>>::{closure#0}
Line
Count
Source
1257
42.3k
    let reader = reader.skip(|r| {
1258
42.3k
        r.read_bytes(len as usize)?;
1259
25.4k
        Ok(())
1260
42.3k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::instances::ComponentInstance>>::{closure#0}
Line
Count
Source
1257
18.9k
    let reader = reader.skip(|r| {
1258
18.9k
        r.read_bytes(len as usize)?;
1259
11.3k
        Ok(())
1260
18.9k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::instances::Instance>>::{closure#0}
Line
Count
Source
1257
56.2k
    let reader = reader.skip(|r| {
1258
56.2k
        r.read_bytes(len as usize)?;
1259
33.7k
        Ok(())
1260
56.2k
    })?;
wasmparser::parser::section::<wasmparser::readers::SectionLimited<u32>>::{closure#0}
Line
Count
Source
1257
67.8k
    let reader = reader.skip(|r| {
1258
67.8k
        r.read_bytes(len as usize)?;
1259
56.3k
        Ok(())
1260
67.8k
    })?;
wasmparser::parser::section::<wasmparser::readers::core::custom::CustomSectionReader>::{closure#0}
Line
Count
Source
1257
165k
    let reader = reader.skip(|r| {
1258
165k
        r.read_bytes(len as usize)?;
1259
114k
        Ok(())
1260
165k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
918k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
918k
    Ok(variant(reader))
1266
1.32M
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::data::Data>>
Line
Count
Source
1251
8.59k
fn section<'a, T>(
1252
8.59k
    reader: &mut BinaryReader<'a>,
1253
8.59k
    len: u32,
1254
8.59k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
8.59k
    variant: fn(T) -> Payload<'a>,
1256
8.59k
) -> Result<Payload<'a>> {
1257
8.59k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
0
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
8.59k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
8.59k
    Ok(variant(reader))
1266
8.59k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::types::MemoryType>>
Line
Count
Source
1251
53.4k
fn section<'a, T>(
1252
53.4k
    reader: &mut BinaryReader<'a>,
1253
53.4k
    len: u32,
1254
53.4k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
53.4k
    variant: fn(T) -> Payload<'a>,
1256
53.4k
) -> Result<Payload<'a>> {
1257
53.4k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
8.77k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
44.6k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
44.6k
    Ok(variant(reader))
1266
53.4k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::types::TagType>>
Line
Count
Source
1251
3.10k
fn section<'a, T>(
1252
3.10k
    reader: &mut BinaryReader<'a>,
1253
3.10k
    len: u32,
1254
3.10k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
3.10k
    variant: fn(T) -> Payload<'a>,
1256
3.10k
) -> Result<Payload<'a>> {
1257
3.10k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
0
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
3.10k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
3.10k
    Ok(variant(reader))
1266
3.10k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::types::RecGroup>>
Line
Count
Source
1251
95.3k
fn section<'a, T>(
1252
95.3k
    reader: &mut BinaryReader<'a>,
1253
95.3k
    len: u32,
1254
95.3k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
95.3k
    variant: fn(T) -> Payload<'a>,
1256
95.3k
) -> Result<Payload<'a>> {
1257
95.3k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
19.5k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
75.7k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
75.7k
    Ok(variant(reader))
1266
95.3k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::tables::Table>>
Line
Count
Source
1251
15.5k
fn section<'a, T>(
1252
15.5k
    reader: &mut BinaryReader<'a>,
1253
15.5k
    len: u32,
1254
15.5k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
15.5k
    variant: fn(T) -> Payload<'a>,
1256
15.5k
) -> Result<Payload<'a>> {
1257
15.5k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
1.31k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
14.2k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
14.2k
    Ok(variant(reader))
1266
15.5k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::exports::Export>>
Line
Count
Source
1251
57.5k
fn section<'a, T>(
1252
57.5k
    reader: &mut BinaryReader<'a>,
1253
57.5k
    len: u32,
1254
57.5k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
57.5k
    variant: fn(T) -> Payload<'a>,
1256
57.5k
) -> Result<Payload<'a>> {
1257
57.5k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
10.8k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
46.7k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
46.7k
    Ok(variant(reader))
1266
57.5k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::globals::Global>>
Line
Count
Source
1251
23.3k
fn section<'a, T>(
1252
23.3k
    reader: &mut BinaryReader<'a>,
1253
23.3k
    len: u32,
1254
23.3k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
23.3k
    variant: fn(T) -> Payload<'a>,
1256
23.3k
) -> Result<Payload<'a>> {
1257
23.3k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
716
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
22.6k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
22.6k
    Ok(variant(reader))
1266
23.3k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::imports::Imports>>
Line
Count
Source
1251
54.8k
fn section<'a, T>(
1252
54.8k
    reader: &mut BinaryReader<'a>,
1253
54.8k
    len: u32,
1254
54.8k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
54.8k
    variant: fn(T) -> Payload<'a>,
1256
54.8k
) -> Result<Payload<'a>> {
1257
54.8k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
12.0k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
42.7k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
42.7k
    Ok(variant(reader))
1266
54.8k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::core::elements::Element>>
Line
Count
Source
1251
13.3k
fn section<'a, T>(
1252
13.3k
    reader: &mut BinaryReader<'a>,
1253
13.3k
    len: u32,
1254
13.3k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
13.3k
    variant: fn(T) -> Payload<'a>,
1256
13.3k
) -> Result<Payload<'a>> {
1257
13.3k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
2.03k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
11.3k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
11.3k
    Ok(variant(reader))
1266
13.3k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::canonicals::CanonicalFunction>>
Line
Count
Source
1251
60.3k
fn section<'a, T>(
1252
60.3k
    reader: &mut BinaryReader<'a>,
1253
60.3k
    len: u32,
1254
60.3k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
60.3k
    variant: fn(T) -> Payload<'a>,
1256
60.3k
) -> Result<Payload<'a>> {
1257
60.3k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
24.1k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
36.2k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
36.2k
    Ok(variant(reader))
1266
60.3k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::types::ComponentType>>
Line
Count
Source
1251
276k
fn section<'a, T>(
1252
276k
    reader: &mut BinaryReader<'a>,
1253
276k
    len: u32,
1254
276k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
276k
    variant: fn(T) -> Payload<'a>,
1256
276k
) -> Result<Payload<'a>> {
1257
276k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
102k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
174k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
174k
    Ok(variant(reader))
1266
276k
}
Unexecuted instantiation: wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::types::CoreType>>
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::aliases::ComponentAlias>>
Line
Count
Source
1251
72.5k
fn section<'a, T>(
1252
72.5k
    reader: &mut BinaryReader<'a>,
1253
72.5k
    len: u32,
1254
72.5k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
72.5k
    variant: fn(T) -> Payload<'a>,
1256
72.5k
) -> Result<Payload<'a>> {
1257
72.5k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
29.0k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
43.5k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
43.5k
    Ok(variant(reader))
1266
72.5k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::exports::ComponentExport>>
Line
Count
Source
1251
240k
fn section<'a, T>(
1252
240k
    reader: &mut BinaryReader<'a>,
1253
240k
    len: u32,
1254
240k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
240k
    variant: fn(T) -> Payload<'a>,
1256
240k
) -> Result<Payload<'a>> {
1257
240k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
87.8k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
152k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
152k
    Ok(variant(reader))
1266
240k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::imports::ComponentImport>>
Line
Count
Source
1251
42.3k
fn section<'a, T>(
1252
42.3k
    reader: &mut BinaryReader<'a>,
1253
42.3k
    len: u32,
1254
42.3k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
42.3k
    variant: fn(T) -> Payload<'a>,
1256
42.3k
) -> Result<Payload<'a>> {
1257
42.3k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
16.9k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
25.4k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
25.4k
    Ok(variant(reader))
1266
42.3k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::instances::ComponentInstance>>
Line
Count
Source
1251
18.9k
fn section<'a, T>(
1252
18.9k
    reader: &mut BinaryReader<'a>,
1253
18.9k
    len: u32,
1254
18.9k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
18.9k
    variant: fn(T) -> Payload<'a>,
1256
18.9k
) -> Result<Payload<'a>> {
1257
18.9k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
7.57k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
11.3k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
11.3k
    Ok(variant(reader))
1266
18.9k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<wasmparser::readers::component::instances::Instance>>
Line
Count
Source
1251
56.2k
fn section<'a, T>(
1252
56.2k
    reader: &mut BinaryReader<'a>,
1253
56.2k
    len: u32,
1254
56.2k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
56.2k
    variant: fn(T) -> Payload<'a>,
1256
56.2k
) -> Result<Payload<'a>> {
1257
56.2k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
22.5k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
33.7k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
33.7k
    Ok(variant(reader))
1266
56.2k
}
wasmparser::parser::section::<wasmparser::readers::SectionLimited<u32>>
Line
Count
Source
1251
67.8k
fn section<'a, T>(
1252
67.8k
    reader: &mut BinaryReader<'a>,
1253
67.8k
    len: u32,
1254
67.8k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
67.8k
    variant: fn(T) -> Payload<'a>,
1256
67.8k
) -> Result<Payload<'a>> {
1257
67.8k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
11.5k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
56.3k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
56.3k
    Ok(variant(reader))
1266
67.8k
}
wasmparser::parser::section::<wasmparser::readers::core::custom::CustomSectionReader>
Line
Count
Source
1251
165k
fn section<'a, T>(
1252
165k
    reader: &mut BinaryReader<'a>,
1253
165k
    len: u32,
1254
165k
    ctor: fn(BinaryReader<'a>) -> Result<T>,
1255
165k
    variant: fn(T) -> Payload<'a>,
1256
165k
) -> Result<Payload<'a>> {
1257
165k
    let reader = reader.skip(|r| {
1258
        r.read_bytes(len as usize)?;
1259
        Ok(())
1260
51.1k
    })?;
1261
    // clear the hint for "need this many more bytes" here because we already
1262
    // read all the bytes, so it's not possible to read more bytes if this
1263
    // fails.
1264
114k
    let reader = ctor(reader).map_err(Error::without_needed_hint)?;
1265
114k
    Ok(variant(reader))
1266
165k
}
1267
1268
/// Reads a section that is represented by a single uleb-encoded `u32`.
1269
29.9k
fn single_item<'a, T>(
1270
29.9k
    reader: &mut BinaryReader<'a>,
1271
29.9k
    section_end: u64,
1272
29.9k
    desc: &str,
1273
29.9k
) -> Result<(T, Range<u64>)>
1274
29.9k
where
1275
29.9k
    T: FromReader<'a>,
1276
{
1277
29.9k
    let range = reader.original_position()..section_end;
1278
29.9k
    let mut content = reader.skip(|r| {
1279
        // length is guaranteed to fit into a u32
1280
29.9k
        r.read_bytes((range.end - range.start) as u32 as usize)?;
1281
21.1k
        Ok(())
1282
29.9k
    })?;
Unexecuted instantiation: wasmparser::parser::single_item::<wasmparser::readers::component::start::ComponentStartFunction>::{closure#0}
wasmparser::parser::single_item::<u32>::{closure#0}
Line
Count
Source
1278
29.9k
    let mut content = reader.skip(|r| {
1279
        // length is guaranteed to fit into a u32
1280
29.9k
        r.read_bytes((range.end - range.start) as u32 as usize)?;
1281
21.1k
        Ok(())
1282
29.9k
    })?;
1283
    // We can't recover from "unexpected eof" here because our entire section is
1284
    // already resident in memory, so clear the hint for how many more bytes are
1285
    // expected.
1286
21.1k
    let ret = content.read().map_err(Error::without_needed_hint)?;
1287
21.1k
    if !content.eof() {
1288
0
        bail!(
1289
0
            content.original_position(),
1290
            "unexpected content in the {desc} section",
1291
        );
1292
21.1k
    }
1293
21.1k
    Ok((ret, range))
1294
29.9k
}
Unexecuted instantiation: wasmparser::parser::single_item::<wasmparser::readers::component::start::ComponentStartFunction>
wasmparser::parser::single_item::<u32>
Line
Count
Source
1269
29.9k
fn single_item<'a, T>(
1270
29.9k
    reader: &mut BinaryReader<'a>,
1271
29.9k
    section_end: u64,
1272
29.9k
    desc: &str,
1273
29.9k
) -> Result<(T, Range<u64>)>
1274
29.9k
where
1275
29.9k
    T: FromReader<'a>,
1276
{
1277
29.9k
    let range = reader.original_position()..section_end;
1278
29.9k
    let mut content = reader.skip(|r| {
1279
        // length is guaranteed to fit into a u32
1280
        r.read_bytes((range.end - range.start) as u32 as usize)?;
1281
        Ok(())
1282
8.77k
    })?;
1283
    // We can't recover from "unexpected eof" here because our entire section is
1284
    // already resident in memory, so clear the hint for how many more bytes are
1285
    // expected.
1286
21.1k
    let ret = content.read().map_err(Error::without_needed_hint)?;
1287
21.1k
    if !content.eof() {
1288
0
        bail!(
1289
0
            content.original_position(),
1290
            "unexpected content in the {desc} section",
1291
        );
1292
21.1k
    }
1293
21.1k
    Ok((ret, range))
1294
29.9k
}
1295
1296
/// Attempts to parse using `f`.
1297
///
1298
/// This will update `*len` with the number of bytes consumed, and it will cause
1299
/// a failure to be returned instead of the number of bytes consumed exceeds
1300
/// what `*len` currently is.
1301
765k
fn delimited<'a, T>(
1302
765k
    reader: &mut BinaryReader<'a>,
1303
765k
    len: &mut u32,
1304
765k
    f: impl FnOnce(&mut BinaryReader<'a>) -> Result<T>,
1305
765k
) -> Result<T> {
1306
765k
    let start = reader.original_position();
1307
765k
    let ret = f(reader)?;
1308
657k
    *len = match (reader.original_position() - start)
1309
657k
        .try_into()
1310
657k
        .ok()
1311
657k
        .and_then(|i| len.checked_sub(i))
wasmparser::parser::delimited::<wasmparser::readers::core::code::FunctionBody, <wasmparser::parser::Parser>::parse_reader::{closure#2}>::{closure#0}
Line
Count
Source
1311
601k
        .and_then(|i| len.checked_sub(i))
wasmparser::parser::delimited::<u32, <wasmparser::parser::Parser>::parse_reader::{closure#1}>::{closure#0}
Line
Count
Source
1311
56.2k
        .and_then(|i| len.checked_sub(i))
1312
    {
1313
657k
        Some(i) => i,
1314
0
        None => return Err(Error::new("unexpected end-of-file", start)),
1315
    };
1316
657k
    Ok(ret)
1317
765k
}
wasmparser::parser::delimited::<wasmparser::readers::core::code::FunctionBody, <wasmparser::parser::Parser>::parse_reader::{closure#2}>
Line
Count
Source
1301
698k
fn delimited<'a, T>(
1302
698k
    reader: &mut BinaryReader<'a>,
1303
698k
    len: &mut u32,
1304
698k
    f: impl FnOnce(&mut BinaryReader<'a>) -> Result<T>,
1305
698k
) -> Result<T> {
1306
698k
    let start = reader.original_position();
1307
698k
    let ret = f(reader)?;
1308
601k
    *len = match (reader.original_position() - start)
1309
601k
        .try_into()
1310
601k
        .ok()
1311
601k
        .and_then(|i| len.checked_sub(i))
1312
    {
1313
601k
        Some(i) => i,
1314
0
        None => return Err(Error::new("unexpected end-of-file", start)),
1315
    };
1316
601k
    Ok(ret)
1317
698k
}
wasmparser::parser::delimited::<u32, <wasmparser::parser::Parser>::parse_reader::{closure#1}>
Line
Count
Source
1301
67.7k
fn delimited<'a, T>(
1302
67.7k
    reader: &mut BinaryReader<'a>,
1303
67.7k
    len: &mut u32,
1304
67.7k
    f: impl FnOnce(&mut BinaryReader<'a>) -> Result<T>,
1305
67.7k
) -> Result<T> {
1306
67.7k
    let start = reader.original_position();
1307
67.7k
    let ret = f(reader)?;
1308
56.2k
    *len = match (reader.original_position() - start)
1309
56.2k
        .try_into()
1310
56.2k
        .ok()
1311
56.2k
        .and_then(|i| len.checked_sub(i))
1312
    {
1313
56.2k
        Some(i) => i,
1314
0
        None => return Err(Error::new("unexpected end-of-file", start)),
1315
    };
1316
56.2k
    Ok(ret)
1317
67.7k
}
1318
1319
impl Default for Parser {
1320
575
    fn default() -> Parser {
1321
575
        Parser::new(0)
1322
575
    }
1323
}
1324
1325
impl Payload<'_> {
1326
    /// If this `Payload` represents a section in the original wasm module then
1327
    /// the section's id and range within the original wasm binary are returned.
1328
    ///
1329
    /// Not all payloads refer to entire sections, such as the `Version` and
1330
    /// `CodeSectionEntry` variants. These variants will return `None` from this
1331
    /// function.
1332
    ///
1333
    /// Otherwise this function will return `Some` where the first element is
1334
    /// the byte identifier for the section and the second element is the range
1335
    /// of the contents of the section within the original wasm binary.
1336
    ///
1337
    /// The purpose of this method is to enable tools to easily iterate over
1338
    /// entire sections if necessary and handle sections uniformly, for example
1339
    /// dropping custom sections while preserving all other sections.
1340
152k
    pub fn as_section(&self) -> Option<(u8, Range<u64>)> {
1341
        use Payload::*;
1342
1343
152k
        match self {
1344
13.1k
            Version { .. } => None,
1345
13.1k
            TypeSection(s) => Some((TYPE_SECTION, s.range())),
1346
3.26k
            ImportSection(s) => Some((IMPORT_SECTION, s.range())),
1347
13.1k
            FunctionSection(s) => Some((FUNCTION_SECTION, s.range())),
1348
0
            TableSection(s) => Some((TABLE_SECTION, s.range())),
1349
13.1k
            MemorySection(s) => Some((MEMORY_SECTION, s.range())),
1350
0
            TagSection(s) => Some((TAG_SECTION, s.range())),
1351
0
            GlobalSection(s) => Some((GLOBAL_SECTION, s.range())),
1352
13.1k
            ExportSection(s) => Some((EXPORT_SECTION, s.range())),
1353
0
            ElementSection(s) => Some((ELEMENT_SECTION, s.range())),
1354
0
            DataSection(s) => Some((DATA_SECTION, s.range())),
1355
0
            StartSection { range, .. } => Some((START_SECTION, range.clone())),
1356
0
            DataCountSection { range, .. } => Some((DATA_COUNT_SECTION, range.clone())),
1357
13.1k
            CodeSectionStart { range, .. } => Some((CODE_SECTION, range.clone())),
1358
61.6k
            CodeSectionEntry(_) => None,
1359
1360
            #[cfg(feature = "component-model")]
1361
            ModuleSection {
1362
0
                unchecked_range: range,
1363
                ..
1364
0
            } => Some((COMPONENT_MODULE_SECTION, range.clone())),
1365
            #[cfg(feature = "component-model")]
1366
0
            InstanceSection(s) => Some((COMPONENT_CORE_INSTANCE_SECTION, s.range())),
1367
            #[cfg(feature = "component-model")]
1368
0
            CoreTypeSection(s) => Some((COMPONENT_CORE_TYPE_SECTION, s.range())),
1369
            #[cfg(feature = "component-model")]
1370
            ComponentSection {
1371
0
                unchecked_range: range,
1372
                ..
1373
0
            } => Some((COMPONENT_SECTION, range.clone())),
1374
            #[cfg(feature = "component-model")]
1375
0
            ComponentInstanceSection(s) => Some((COMPONENT_INSTANCE_SECTION, s.range())),
1376
            #[cfg(feature = "component-model")]
1377
0
            ComponentAliasSection(s) => Some((COMPONENT_ALIAS_SECTION, s.range())),
1378
            #[cfg(feature = "component-model")]
1379
0
            ComponentTypeSection(s) => Some((COMPONENT_TYPE_SECTION, s.range())),
1380
            #[cfg(feature = "component-model")]
1381
0
            ComponentCanonicalSection(s) => Some((COMPONENT_CANONICAL_SECTION, s.range())),
1382
            #[cfg(feature = "component-model")]
1383
0
            ComponentStartSection { range, .. } => Some((COMPONENT_START_SECTION, range.clone())),
1384
            #[cfg(feature = "component-model")]
1385
0
            ComponentImportSection(s) => Some((COMPONENT_IMPORT_SECTION, s.range())),
1386
            #[cfg(feature = "component-model")]
1387
0
            ComponentExportSection(s) => Some((COMPONENT_EXPORT_SECTION, s.range())),
1388
1389
0
            CustomSection(c) => Some((CUSTOM_SECTION, c.range())),
1390
1391
0
            UnknownSection { id, range, .. } => Some((*id, range.clone())),
1392
1393
8.77k
            End(_) => None,
1394
        }
1395
152k
    }
1396
}
1397
1398
impl fmt::Debug for Payload<'_> {
1399
159
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1400
        use Payload::*;
1401
159
        match self {
1402
            Version {
1403
0
                num,
1404
0
                encoding,
1405
0
                range,
1406
0
            } => f
1407
0
                .debug_struct("Version")
1408
0
                .field("num", num)
1409
0
                .field("encoding", encoding)
1410
0
                .field("range", range)
1411
0
                .finish(),
1412
1413
            // Module sections
1414
0
            TypeSection(_) => f.debug_tuple("TypeSection").field(&"...").finish(),
1415
0
            ImportSection(_) => f.debug_tuple("ImportSection").field(&"...").finish(),
1416
0
            FunctionSection(_) => f.debug_tuple("FunctionSection").field(&"...").finish(),
1417
0
            TableSection(_) => f.debug_tuple("TableSection").field(&"...").finish(),
1418
0
            MemorySection(_) => f.debug_tuple("MemorySection").field(&"...").finish(),
1419
159
            TagSection(_) => f.debug_tuple("TagSection").field(&"...").finish(),
1420
0
            GlobalSection(_) => f.debug_tuple("GlobalSection").field(&"...").finish(),
1421
0
            ExportSection(_) => f.debug_tuple("ExportSection").field(&"...").finish(),
1422
0
            ElementSection(_) => f.debug_tuple("ElementSection").field(&"...").finish(),
1423
0
            DataSection(_) => f.debug_tuple("DataSection").field(&"...").finish(),
1424
0
            StartSection { func, range } => f
1425
0
                .debug_struct("StartSection")
1426
0
                .field("func", func)
1427
0
                .field("range", range)
1428
0
                .finish(),
1429
0
            DataCountSection { count, range } => f
1430
0
                .debug_struct("DataCountSection")
1431
0
                .field("count", count)
1432
0
                .field("range", range)
1433
0
                .finish(),
1434
0
            CodeSectionStart { count, range, size } => f
1435
0
                .debug_struct("CodeSectionStart")
1436
0
                .field("count", count)
1437
0
                .field("range", range)
1438
0
                .field("size", size)
1439
0
                .finish(),
1440
0
            CodeSectionEntry(_) => f.debug_tuple("CodeSectionEntry").field(&"...").finish(),
1441
1442
            // Component sections
1443
            #[cfg(feature = "component-model")]
1444
            ModuleSection {
1445
                parser: _,
1446
0
                unchecked_range: range,
1447
0
            } => f
1448
0
                .debug_struct("ModuleSection")
1449
0
                .field("range", range)
1450
0
                .finish(),
1451
            #[cfg(feature = "component-model")]
1452
0
            InstanceSection(_) => f.debug_tuple("InstanceSection").field(&"...").finish(),
1453
            #[cfg(feature = "component-model")]
1454
0
            CoreTypeSection(_) => f.debug_tuple("CoreTypeSection").field(&"...").finish(),
1455
            #[cfg(feature = "component-model")]
1456
            ComponentSection {
1457
                parser: _,
1458
0
                unchecked_range: range,
1459
0
            } => f
1460
0
                .debug_struct("ComponentSection")
1461
0
                .field("range", range)
1462
0
                .finish(),
1463
            #[cfg(feature = "component-model")]
1464
0
            ComponentInstanceSection(_) => f
1465
0
                .debug_tuple("ComponentInstanceSection")
1466
0
                .field(&"...")
1467
0
                .finish(),
1468
            #[cfg(feature = "component-model")]
1469
0
            ComponentAliasSection(_) => f
1470
0
                .debug_tuple("ComponentAliasSection")
1471
0
                .field(&"...")
1472
0
                .finish(),
1473
            #[cfg(feature = "component-model")]
1474
0
            ComponentTypeSection(_) => f.debug_tuple("ComponentTypeSection").field(&"...").finish(),
1475
            #[cfg(feature = "component-model")]
1476
0
            ComponentCanonicalSection(_) => f
1477
0
                .debug_tuple("ComponentCanonicalSection")
1478
0
                .field(&"...")
1479
0
                .finish(),
1480
            #[cfg(feature = "component-model")]
1481
0
            ComponentStartSection { .. } => f
1482
0
                .debug_tuple("ComponentStartSection")
1483
0
                .field(&"...")
1484
0
                .finish(),
1485
            #[cfg(feature = "component-model")]
1486
0
            ComponentImportSection(_) => f
1487
0
                .debug_tuple("ComponentImportSection")
1488
0
                .field(&"...")
1489
0
                .finish(),
1490
            #[cfg(feature = "component-model")]
1491
0
            ComponentExportSection(_) => f
1492
0
                .debug_tuple("ComponentExportSection")
1493
0
                .field(&"...")
1494
0
                .finish(),
1495
1496
0
            CustomSection(c) => f.debug_tuple("CustomSection").field(c).finish(),
1497
1498
0
            UnknownSection { id, range, .. } => f
1499
0
                .debug_struct("UnknownSection")
1500
0
                .field("id", id)
1501
0
                .field("range", range)
1502
0
                .finish(),
1503
1504
0
            End(offset) => f.debug_tuple("End").field(offset).finish(),
1505
        }
1506
159
    }
1507
}
1508
1509
#[cfg(test)]
1510
mod tests {
1511
    use super::*;
1512
1513
    macro_rules! assert_matches {
1514
        ($a:expr, $b:pat $(,)?) => {
1515
            match $a {
1516
                $b => {}
1517
                a => panic!("`{:?}` doesn't match `{}`", a, stringify!($b)),
1518
            }
1519
        };
1520
    }
1521
1522
    #[test]
1523
    fn header() {
1524
        assert!(Parser::default().parse(&[], true).is_err());
1525
        assert_matches!(
1526
            Parser::default().parse(&[], false),
1527
            Ok(Chunk::NeedMoreData(4)),
1528
        );
1529
        assert_matches!(
1530
            Parser::default().parse(b"\0", false),
1531
            Ok(Chunk::NeedMoreData(3)),
1532
        );
1533
        assert_matches!(
1534
            Parser::default().parse(b"\0asm", false),
1535
            Ok(Chunk::NeedMoreData(4)),
1536
        );
1537
        assert_matches!(
1538
            Parser::default().parse(b"\0asm\x01\0\0\0", false),
1539
            Ok(Chunk::Parsed {
1540
                consumed: 8,
1541
                payload: Payload::Version { num: 1, .. },
1542
            }),
1543
        );
1544
    }
1545
1546
    #[test]
1547
    fn header_iter() {
1548
        for _ in Parser::default().parse_all(&[]) {}
1549
        for _ in Parser::default().parse_all(b"\0") {}
1550
        for _ in Parser::default().parse_all(b"\0asm") {}
1551
        for _ in Parser::default().parse_all(b"\0asm\x01\x01\x01\x01") {}
1552
    }
1553
1554
    fn parser_after_header() -> Parser {
1555
        let mut p = Parser::default();
1556
        assert_matches!(
1557
            p.parse(b"\0asm\x01\0\0\0", false),
1558
            Ok(Chunk::Parsed {
1559
                consumed: 8,
1560
                payload: Payload::Version {
1561
                    num: WASM_MODULE_VERSION,
1562
                    encoding: Encoding::Module,
1563
                    ..
1564
                },
1565
            }),
1566
        );
1567
        p
1568
    }
1569
1570
    fn parser_after_component_header() -> Parser {
1571
        let mut p = Parser::default();
1572
        assert_matches!(
1573
            p.parse(b"\0asm\x0d\0\x01\0", false),
1574
            Ok(Chunk::Parsed {
1575
                consumed: 8,
1576
                payload: Payload::Version {
1577
                    num: WASM_COMPONENT_VERSION,
1578
                    encoding: Encoding::Component,
1579
                    ..
1580
                },
1581
            }),
1582
        );
1583
        p
1584
    }
1585
1586
    #[test]
1587
    fn start_section() {
1588
        assert_matches!(
1589
            parser_after_header().parse(&[], false),
1590
            Ok(Chunk::NeedMoreData(1)),
1591
        );
1592
        assert!(parser_after_header().parse(&[8], true).is_err());
1593
        assert!(parser_after_header().parse(&[8, 1], true).is_err());
1594
        assert!(parser_after_header().parse(&[8, 2], true).is_err());
1595
        assert_matches!(
1596
            parser_after_header().parse(&[8], false),
1597
            Ok(Chunk::NeedMoreData(1)),
1598
        );
1599
        assert_matches!(
1600
            parser_after_header().parse(&[8, 1], false),
1601
            Ok(Chunk::NeedMoreData(1)),
1602
        );
1603
        assert_matches!(
1604
            parser_after_header().parse(&[8, 2], false),
1605
            Ok(Chunk::NeedMoreData(2)),
1606
        );
1607
        assert_matches!(
1608
            parser_after_header().parse(&[8, 1, 1], false),
1609
            Ok(Chunk::Parsed {
1610
                consumed: 3,
1611
                payload: Payload::StartSection { func: 1, .. },
1612
            }),
1613
        );
1614
        assert!(parser_after_header().parse(&[8, 2, 1, 1], false).is_err());
1615
        assert!(parser_after_header().parse(&[8, 0], false).is_err());
1616
    }
1617
1618
    #[test]
1619
    fn end_works() {
1620
        assert_matches!(
1621
            parser_after_header().parse(&[], true),
1622
            Ok(Chunk::Parsed {
1623
                consumed: 0,
1624
                payload: Payload::End(8),
1625
            }),
1626
        );
1627
    }
1628
1629
    #[test]
1630
    fn type_section() {
1631
        assert!(parser_after_header().parse(&[1], true).is_err());
1632
        assert!(parser_after_header().parse(&[1, 0], false).is_err());
1633
        assert!(parser_after_header().parse(&[8, 2], true).is_err());
1634
        assert_matches!(
1635
            parser_after_header().parse(&[1], false),
1636
            Ok(Chunk::NeedMoreData(1)),
1637
        );
1638
        assert_matches!(
1639
            parser_after_header().parse(&[1, 1], false),
1640
            Ok(Chunk::NeedMoreData(1)),
1641
        );
1642
        assert_matches!(
1643
            parser_after_header().parse(&[1, 1, 1], false),
1644
            Ok(Chunk::Parsed {
1645
                consumed: 3,
1646
                payload: Payload::TypeSection(_),
1647
            }),
1648
        );
1649
        assert_matches!(
1650
            parser_after_header().parse(&[1, 1, 1, 2, 3, 4], false),
1651
            Ok(Chunk::Parsed {
1652
                consumed: 3,
1653
                payload: Payload::TypeSection(_),
1654
            }),
1655
        );
1656
    }
1657
1658
    #[test]
1659
    fn custom_section() {
1660
        assert!(parser_after_header().parse(&[0], true).is_err());
1661
        assert!(parser_after_header().parse(&[0, 0], false).is_err());
1662
        assert!(parser_after_header().parse(&[0, 1, 1], false).is_err());
1663
        assert_matches!(
1664
            parser_after_header().parse(&[0, 2, 1], false),
1665
            Ok(Chunk::NeedMoreData(1)),
1666
        );
1667
        assert_custom(
1668
            parser_after_header().parse(&[0, 1, 0], false).unwrap(),
1669
            3,
1670
            "",
1671
            11,
1672
            b"",
1673
            Range { start: 10, end: 11 },
1674
        );
1675
        assert_custom(
1676
            parser_after_header()
1677
                .parse(&[0, 2, 1, b'a'], false)
1678
                .unwrap(),
1679
            4,
1680
            "a",
1681
            12,
1682
            b"",
1683
            Range { start: 10, end: 12 },
1684
        );
1685
        assert_custom(
1686
            parser_after_header()
1687
                .parse(&[0, 2, 0, b'a'], false)
1688
                .unwrap(),
1689
            4,
1690
            "",
1691
            11,
1692
            b"a",
1693
            Range { start: 10, end: 12 },
1694
        );
1695
    }
1696
1697
    fn assert_custom(
1698
        chunk: Chunk<'_>,
1699
        expected_consumed: usize,
1700
        expected_name: &str,
1701
        expected_data_offset: u64,
1702
        expected_data: &[u8],
1703
        expected_range: Range<u64>,
1704
    ) {
1705
        let (consumed, s) = match chunk {
1706
            Chunk::Parsed {
1707
                consumed,
1708
                payload: Payload::CustomSection(s),
1709
            } => (consumed, s),
1710
            _ => panic!("not a custom section payload"),
1711
        };
1712
        assert_eq!(consumed, expected_consumed);
1713
        assert_eq!(s.name(), expected_name);
1714
        assert_eq!(s.data_offset(), expected_data_offset);
1715
        assert_eq!(s.data(), expected_data);
1716
        assert_eq!(s.range(), expected_range);
1717
    }
1718
1719
    #[test]
1720
    fn function_section() {
1721
        assert!(parser_after_header().parse(&[10], true).is_err());
1722
        assert!(parser_after_header().parse(&[10, 0], true).is_err());
1723
        assert!(parser_after_header().parse(&[10, 1], true).is_err());
1724
        assert_matches!(
1725
            parser_after_header().parse(&[10], false),
1726
            Ok(Chunk::NeedMoreData(1))
1727
        );
1728
        assert_matches!(
1729
            parser_after_header().parse(&[10, 1], false),
1730
            Ok(Chunk::NeedMoreData(1))
1731
        );
1732
        let mut p = parser_after_header();
1733
        assert_matches!(
1734
            p.parse(&[10, 1, 0], false),
1735
            Ok(Chunk::Parsed {
1736
                consumed: 3,
1737
                payload: Payload::CodeSectionStart { count: 0, .. },
1738
            }),
1739
        );
1740
        assert_matches!(
1741
            p.parse(&[], true),
1742
            Ok(Chunk::Parsed {
1743
                consumed: 0,
1744
                payload: Payload::End(11),
1745
            }),
1746
        );
1747
        let mut p = parser_after_header();
1748
        assert_matches!(
1749
            p.parse(&[3, 2, 1, 0], false),
1750
            Ok(Chunk::Parsed {
1751
                consumed: 4,
1752
                payload: Payload::FunctionSection { .. },
1753
            }),
1754
        );
1755
        assert_matches!(
1756
            p.parse(&[10, 2, 1, 0], false),
1757
            Ok(Chunk::Parsed {
1758
                consumed: 3,
1759
                payload: Payload::CodeSectionStart { count: 1, .. },
1760
            }),
1761
        );
1762
        assert_matches!(
1763
            p.parse(&[0], false),
1764
            Ok(Chunk::Parsed {
1765
                consumed: 1,
1766
                payload: Payload::CodeSectionEntry(_),
1767
            }),
1768
        );
1769
        assert_matches!(
1770
            p.parse(&[], true),
1771
            Ok(Chunk::Parsed {
1772
                consumed: 0,
1773
                payload: Payload::End(16),
1774
            }),
1775
        );
1776
1777
        // 1 byte section with 1 function can't read the function body because
1778
        // the section is too small
1779
        let mut p = parser_after_header();
1780
        assert_matches!(
1781
            p.parse(&[3, 2, 1, 0], false),
1782
            Ok(Chunk::Parsed {
1783
                consumed: 4,
1784
                payload: Payload::FunctionSection { .. },
1785
            }),
1786
        );
1787
        assert_matches!(
1788
            p.parse(&[10, 1, 1], false),
1789
            Ok(Chunk::Parsed {
1790
                consumed: 3,
1791
                payload: Payload::CodeSectionStart { count: 1, .. },
1792
            }),
1793
        );
1794
        assert_eq!(
1795
            p.parse(&[0], false).unwrap_err().message(),
1796
            "unexpected end-of-file"
1797
        );
1798
1799
        // section with 2 functions but section is cut off
1800
        let mut p = parser_after_header();
1801
        assert_matches!(
1802
            p.parse(&[3, 2, 2, 0], false),
1803
            Ok(Chunk::Parsed {
1804
                consumed: 4,
1805
                payload: Payload::FunctionSection { .. },
1806
            }),
1807
        );
1808
        assert_matches!(
1809
            p.parse(&[10, 2, 2], false),
1810
            Ok(Chunk::Parsed {
1811
                consumed: 3,
1812
                payload: Payload::CodeSectionStart { count: 2, .. },
1813
            }),
1814
        );
1815
        assert_matches!(
1816
            p.parse(&[0], false),
1817
            Ok(Chunk::Parsed {
1818
                consumed: 1,
1819
                payload: Payload::CodeSectionEntry(_),
1820
            }),
1821
        );
1822
        assert_matches!(p.parse(&[], false), Ok(Chunk::NeedMoreData(1)));
1823
        assert_eq!(
1824
            p.parse(&[0], false).unwrap_err().message(),
1825
            "unexpected end-of-file",
1826
        );
1827
1828
        // trailing data is bad
1829
        let mut p = parser_after_header();
1830
        assert_matches!(
1831
            p.parse(&[3, 2, 1, 0], false),
1832
            Ok(Chunk::Parsed {
1833
                consumed: 4,
1834
                payload: Payload::FunctionSection { .. },
1835
            }),
1836
        );
1837
        assert_matches!(
1838
            p.parse(&[10, 3, 1], false),
1839
            Ok(Chunk::Parsed {
1840
                consumed: 3,
1841
                payload: Payload::CodeSectionStart { count: 1, .. },
1842
            }),
1843
        );
1844
        assert_matches!(
1845
            p.parse(&[0], false),
1846
            Ok(Chunk::Parsed {
1847
                consumed: 1,
1848
                payload: Payload::CodeSectionEntry(_),
1849
            }),
1850
        );
1851
        assert_eq!(
1852
            p.parse(&[0], false).unwrap_err().message(),
1853
            "trailing bytes at end of section",
1854
        );
1855
    }
1856
1857
    #[test]
1858
    fn single_module() {
1859
        let mut p = parser_after_component_header();
1860
        assert_matches!(p.parse(&[4], false), Ok(Chunk::NeedMoreData(1)));
1861
1862
        // A module that's 8 bytes in length
1863
        let mut sub = match p.parse(&[1, 8], false) {
1864
            Ok(Chunk::Parsed {
1865
                consumed: 2,
1866
                payload: Payload::ModuleSection { parser, .. },
1867
            }) => parser,
1868
            other => panic!("bad parse {other:?}"),
1869
        };
1870
1871
        // Parse the header of the submodule with the sub-parser.
1872
        assert_matches!(sub.parse(&[], false), Ok(Chunk::NeedMoreData(4)));
1873
        assert_matches!(sub.parse(b"\0asm", false), Ok(Chunk::NeedMoreData(4)));
1874
        assert_matches!(
1875
            sub.parse(b"\0asm\x01\0\0\0", false),
1876
            Ok(Chunk::Parsed {
1877
                consumed: 8,
1878
                payload: Payload::Version {
1879
                    num: 1,
1880
                    encoding: Encoding::Module,
1881
                    ..
1882
                },
1883
            }),
1884
        );
1885
1886
        // The sub-parser should be byte-limited so the next byte shouldn't get
1887
        // consumed, it's intended for the parent parser.
1888
        assert_matches!(
1889
            sub.parse(&[10], false),
1890
            Ok(Chunk::Parsed {
1891
                consumed: 0,
1892
                payload: Payload::End(18),
1893
            }),
1894
        );
1895
1896
        // The parent parser should now be back to resuming, and we simulate it
1897
        // being done with bytes to ensure that it's safely at the end,
1898
        // completing the module code section.
1899
        assert_matches!(p.parse(&[], false), Ok(Chunk::NeedMoreData(1)));
1900
        assert_matches!(
1901
            p.parse(&[], true),
1902
            Ok(Chunk::Parsed {
1903
                consumed: 0,
1904
                payload: Payload::End(18),
1905
            }),
1906
        );
1907
    }
1908
1909
    #[test]
1910
    fn nested_section_too_big() {
1911
        let mut p = parser_after_component_header();
1912
1913
        // A module that's 10 bytes in length
1914
        let mut sub = match p.parse(&[1, 10], false) {
1915
            Ok(Chunk::Parsed {
1916
                consumed: 2,
1917
                payload: Payload::ModuleSection { parser, .. },
1918
            }) => parser,
1919
            other => panic!("bad parse {other:?}"),
1920
        };
1921
1922
        // use 8 bytes to parse the header, leaving 2 remaining bytes in our
1923
        // module.
1924
        assert_matches!(
1925
            sub.parse(b"\0asm\x01\0\0\0", false),
1926
            Ok(Chunk::Parsed {
1927
                consumed: 8,
1928
                payload: Payload::Version { num: 1, .. },
1929
            }),
1930
        );
1931
1932
        // We can't parse a section which declares its bigger than the outer
1933
        // module. This is a custom section, one byte big, with one content byte. The
1934
        // content byte, however, lives outside of the parent's module code
1935
        // section.
1936
        assert!(
1937
            sub.parse(&[0, 1, 0], false)
1938
                .unwrap_err()
1939
                .message()
1940
                .starts_with("section too large")
1941
        );
1942
    }
1943
}