Coverage Report

Created: 2026-07-05 07:39

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