wasmparser/
binary_reader.rs

1/* Copyright 2018 Mozilla Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16use crate::prelude::*;
17use crate::{limits::*, *};
18use core::fmt;
19use core::marker;
20use core::ops::Range;
21use core::str;
22
23pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm";
24
25/// A binary reader for WebAssembly modules.
26#[derive(Debug, Clone)]
27pub struct BinaryReaderError {
28    // Wrap the actual error data in a `Box` so that the error is just one
29    // word. This means that we can continue returning small `Result`s in
30    // registers.
31    pub(crate) inner: Box<BinaryReaderErrorInner>,
32}
33
34#[derive(Debug, Clone)]
35pub(crate) struct BinaryReaderErrorInner {
36    pub(crate) message: String,
37    pub(crate) kind: BinaryReaderErrorKind,
38    pub(crate) offset: usize,
39    pub(crate) needed_hint: Option<usize>,
40}
41
42#[derive(Debug, Clone, Copy)]
43pub(crate) enum BinaryReaderErrorKind {
44    Custom,
45    Invalid,
46}
47
48/// The result for `BinaryReader` operations.
49pub type Result<T, E = BinaryReaderError> = core::result::Result<T, E>;
50
51#[cfg(feature = "std")]
52impl std::error::Error for BinaryReaderError {}
53
54#[cfg(all(not(feature = "std"), core_error))]
55impl core::error::Error for BinaryReaderError {}
56
57impl fmt::Display for BinaryReaderError {
58    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59        write!(
60            f,
61            "{} (at offset 0x{:x})",
62            self.inner.message, self.inner.offset
63        )
64    }
65}
66
67impl BinaryReaderError {
68    #[cold]
69    pub(crate) fn _new(kind: BinaryReaderErrorKind, message: String, offset: usize) -> Self {
70        BinaryReaderError {
71            inner: Box::new(BinaryReaderErrorInner {
72                kind,
73                message,
74                offset,
75                needed_hint: None,
76            }),
77        }
78    }
79
80    #[cold]
81    pub(crate) fn new(message: impl Into<String>, offset: usize) -> Self {
82        Self::_new(BinaryReaderErrorKind::Custom, message.into(), offset)
83    }
84
85    #[cold]
86    pub(crate) fn invalid(msg: &'static str, offset: usize) -> Self {
87        Self::_new(BinaryReaderErrorKind::Invalid, msg.into(), offset)
88    }
89
90    #[cold]
91    pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: usize) -> Self {
92        BinaryReaderError::new(args.to_string(), offset)
93    }
94
95    #[cold]
96    pub(crate) fn eof(offset: usize, needed_hint: usize) -> Self {
97        let mut err = BinaryReaderError::new("unexpected end-of-file", offset);
98        err.inner.needed_hint = Some(needed_hint);
99        err
100    }
101
102    pub(crate) fn kind(&mut self) -> BinaryReaderErrorKind {
103        self.inner.kind
104    }
105
106    /// Get this error's message.
107    pub fn message(&self) -> &str {
108        &self.inner.message
109    }
110
111    /// Get the offset within the Wasm binary where the error occurred.
112    pub fn offset(&self) -> usize {
113        self.inner.offset
114    }
115
116    #[cfg(all(feature = "validate", feature = "component-model"))]
117    pub(crate) fn add_context(&mut self, context: String) {
118        self.inner.message = format!("{context}\n{}", self.inner.message);
119    }
120
121    pub(crate) fn set_message(&mut self, message: &str) {
122        self.inner.message = message.to_string();
123    }
124}
125
126/// A binary reader of the WebAssembly structures and types.
127#[derive(Clone, Debug, Hash)]
128pub struct BinaryReader<'a> {
129    buffer: &'a [u8],
130    position: usize,
131    original_offset: usize,
132
133    // When the `features` feature is disabled then the `WasmFeatures` type
134    // still exists but this field is still omitted. When `features` is
135    // disabled then the only constructor of this type is `BinaryReader::new`
136    // which documents all known features being active. All known features
137    // being active isn't represented by `WasmFeatures` when the feature is
138    // disabled so the field is omitted here to prevent accidentally using the
139    // wrong listing of features.
140    //
141    // Feature accessors are defined by `foreach_wasm_feature!` below with a
142    // method-per-feature on `BinaryReader` which when the `features` feature
143    // is disabled returns `true` by default.
144    #[cfg(feature = "features")]
145    features: WasmFeatures,
146}
147
148impl<'a> BinaryReader<'a> {
149    /// Creates a new binary reader which will parse the `data` provided.
150    ///
151    /// The `original_offset` provided is used for byte offsets in errors that
152    /// are generated. That offset is added to the current position in `data`.
153    /// This can be helpful when `data` is just a window of a view into a larger
154    /// wasm binary perhaps not even entirely stored locally.
155    ///
156    /// The returned binary reader will have all features known to this crate
157    /// enabled. To reject binaries that aren't valid unless a certain feature
158    /// is enabled use the [`BinaryReader::new_features`] constructor instead.
159    pub fn new(data: &[u8], original_offset: usize) -> BinaryReader<'_> {
160        BinaryReader {
161            buffer: data,
162            position: 0,
163            original_offset,
164            #[cfg(feature = "features")]
165            features: WasmFeatures::all(),
166        }
167    }
168
169    /// Creates a new binary reader which will parse the `data` provided.
170    ///
171    /// The `original_offset` provided is used for byte offsets in errors that
172    /// are generated. That offset is added to the current position in `data`.
173    /// This can be helpful when `data` is just a window of a view into a larger
174    /// wasm binary perhaps not even entirely stored locally.
175    ///
176    /// The `features` argument provided controls which WebAssembly features are
177    /// active when parsing this data. Wasm features typically don't affect
178    /// parsing too much and are generally more applicable during
179    /// validation, but features and proposals will often reinterpret
180    /// previously-invalid constructs as now-valid things meaning something
181    /// slightly different. This means that invalid bytes before a feature may
182    /// now be interpreted differently after a feature is implemented. This
183    /// means that the set of activated features can affect what errors are
184    /// generated and when they are generated.
185    ///
186    /// In general it's safe to pass `WasmFeatures::all()` here. There's no
187    /// downside to enabling all features while parsing and only enabling a
188    /// subset of features during validation.
189    ///
190    /// Note that the activated set of features does not guarantee that
191    /// `BinaryReader` will return an error for disabled features. For example
192    /// if SIMD is disabled then SIMD instructions will still be parsed via
193    /// [`BinaryReader::visit_operator`]. Validation must still be performed to
194    /// provide a strict guarantee that if a feature is disabled that a binary
195    /// doesn't leverage the feature. The activated set of features here instead
196    /// only affects locations where preexisting bytes are reinterpreted in
197    /// different ways with future proposals, such as the `memarg` moving from a
198    /// 32-bit offset to a 64-bit offset with the `memory64` proposal.
199    #[cfg(feature = "features")]
200    pub fn new_features(
201        data: &[u8],
202        original_offset: usize,
203        features: WasmFeatures,
204    ) -> BinaryReader<'_> {
205        BinaryReader {
206            buffer: data,
207            position: 0,
208            original_offset,
209            features,
210        }
211    }
212
213    /// "Shrinks" this binary reader to retain only the buffer left-to-parse.
214    ///
215    /// The primary purpose of this method is to change the return value of the
216    /// `range()` method. That method returns the range of the original buffer
217    /// within the wasm binary so calling `range()` on the returned
218    /// `BinaryReader` will return a smaller range than if `range()` is called
219    /// on `self`.
220    ///
221    /// Otherwise parsing values from either `self` or the return value should
222    /// return the same thing.
223    pub(crate) fn shrink(&self) -> BinaryReader<'a> {
224        BinaryReader {
225            buffer: &self.buffer[self.position..],
226            position: 0,
227            original_offset: self.original_offset + self.position,
228            #[cfg(feature = "features")]
229            features: self.features,
230        }
231    }
232
233    /// Gets the original position of the binary reader.
234    #[inline]
235    pub fn original_position(&self) -> usize {
236        self.original_offset + self.position
237    }
238
239    /// Returns the currently active set of wasm features that this reader is
240    /// using while parsing.
241    ///
242    /// For more information see [`BinaryReader::new`].
243    #[cfg(feature = "features")]
244    pub fn features(&self) -> WasmFeatures {
245        self.features
246    }
247
248    /// Sets the wasm features active while parsing to the `features` specified.
249    ///
250    /// For more information see [`BinaryReader::new`].
251    #[cfg(feature = "features")]
252    pub fn set_features(&mut self, features: WasmFeatures) {
253        self.features = features;
254    }
255
256    /// Returns a range from the starting offset to the end of the buffer.
257    pub fn range(&self) -> Range<usize> {
258        self.original_offset..self.original_offset + self.buffer.len()
259    }
260
261    pub(crate) fn remaining_buffer(&self) -> &'a [u8] {
262        &self.buffer[self.position..]
263    }
264
265    fn ensure_has_byte(&self) -> Result<()> {
266        if self.position < self.buffer.len() {
267            Ok(())
268        } else {
269            Err(BinaryReaderError::eof(self.original_position(), 1))
270        }
271    }
272
273    pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result<()> {
274        if self.position + len <= self.buffer.len() {
275            Ok(())
276        } else {
277            let hint = self.position + len - self.buffer.len();
278            Err(BinaryReaderError::eof(self.original_position(), hint))
279        }
280    }
281
282    /// Reads a value of type `T` from this binary reader, advancing the
283    /// internal position in this reader forward as data is read.
284    #[inline]
285    pub fn read<T>(&mut self) -> Result<T>
286    where
287        T: FromReader<'a>,
288    {
289        T::from_reader(self)
290    }
291
292    pub(crate) fn read_u7(&mut self) -> Result<u8> {
293        let b = self.read_u8()?;
294        if (b & 0x80) != 0 {
295            return Err(BinaryReaderError::new(
296                "invalid u7",
297                self.original_position() - 1,
298            ));
299        }
300        Ok(b)
301    }
302
303    pub(crate) fn external_kind_from_byte(byte: u8, offset: usize) -> Result<ExternalKind> {
304        match byte {
305            0x00 => Ok(ExternalKind::Func),
306            0x01 => Ok(ExternalKind::Table),
307            0x02 => Ok(ExternalKind::Memory),
308            0x03 => Ok(ExternalKind::Global),
309            0x04 => Ok(ExternalKind::Tag),
310            x => Err(Self::invalid_leading_byte_error(x, "external kind", offset)),
311        }
312    }
313
314    /// Reads a variable-length 32-bit size from the byte stream while checking
315    /// against a limit.
316    pub fn read_size(&mut self, limit: usize, desc: &str) -> Result<usize> {
317        let pos = self.original_position();
318        let size = self.read_var_u32()? as usize;
319        if size > limit {
320            bail!(pos, "{desc} size is out of bounds");
321        }
322        Ok(size)
323    }
324
325    /// Reads a variable-length 32-bit size from the byte stream while checking
326    /// against a limit.
327    ///
328    /// Then reads that many values of type `T` and returns them as an iterator.
329    ///
330    /// Note that regardless of how many items are read from the returned
331    /// iterator the items will still be parsed from this reader.
332    pub fn read_iter<'me, T>(
333        &'me mut self,
334        limit: usize,
335        desc: &str,
336    ) -> Result<BinaryReaderIter<'a, 'me, T>>
337    where
338        T: FromReader<'a>,
339    {
340        let size = self.read_size(limit, desc)?;
341        Ok(BinaryReaderIter {
342            remaining: size,
343            reader: self,
344            _marker: marker::PhantomData,
345        })
346    }
347
348    /// Returns whether the `BinaryReader` has reached the end of the file.
349    #[inline]
350    pub fn eof(&self) -> bool {
351        self.position >= self.buffer.len()
352    }
353
354    /// Returns the `BinaryReader`'s current position.
355    #[inline]
356    pub fn current_position(&self) -> usize {
357        self.position
358    }
359
360    /// Returns the number of bytes remaining in the `BinaryReader`.
361    #[inline]
362    pub fn bytes_remaining(&self) -> usize {
363        self.buffer.len() - self.position
364    }
365
366    /// Advances the `BinaryReader` `size` bytes, and returns a slice from the
367    /// current position of `size` length.
368    ///
369    /// # Errors
370    /// If `size` exceeds the remaining length in `BinaryReader`.
371    pub fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> {
372        self.ensure_has_bytes(size)?;
373        let start = self.position;
374        self.position += size;
375        Ok(&self.buffer[start..self.position])
376    }
377
378    /// Reads a length-prefixed list of bytes from this reader and returns a
379    /// new `BinaryReader` to read that list of bytes.
380    pub fn read_reader(&mut self) -> Result<BinaryReader<'a>> {
381        let size = self.read_var_u32()? as usize;
382        self.skip(|reader| {
383            reader.read_bytes(size)?;
384            Ok(())
385        })
386    }
387
388    /// Advances the `BinaryReader` four bytes and returns a `u32`.
389    /// # Errors
390    /// If `BinaryReader` has less than four bytes remaining.
391    pub fn read_u32(&mut self) -> Result<u32> {
392        self.ensure_has_bytes(4)?;
393        let word = u32::from_le_bytes(
394            self.buffer[self.position..self.position + 4]
395                .try_into()
396                .unwrap(),
397        );
398        self.position += 4;
399        Ok(word)
400    }
401
402    /// Advances the `BinaryReader` eight bytes and returns a `u64`.
403    /// # Errors
404    /// If `BinaryReader` has less than eight bytes remaining.
405    pub fn read_u64(&mut self) -> Result<u64> {
406        self.ensure_has_bytes(8)?;
407        let word = u64::from_le_bytes(
408            self.buffer[self.position..self.position + 8]
409                .try_into()
410                .unwrap(),
411        );
412        self.position += 8;
413        Ok(word)
414    }
415
416    /// Advances the `BinaryReader` a single byte.
417    ///
418    /// # Errors
419    ///
420    /// If `BinaryReader` has no bytes remaining.
421    #[inline]
422    pub fn read_u8(&mut self) -> Result<u8> {
423        let b = match self.buffer.get(self.position) {
424            Some(b) => *b,
425            None => return Err(self.eof_err()),
426        };
427        self.position += 1;
428        Ok(b)
429    }
430
431    #[cold]
432    fn eof_err(&self) -> BinaryReaderError {
433        BinaryReaderError::eof(self.original_position(), 1)
434    }
435
436    /// Advances the `BinaryReader` up to four bytes to parse a variable
437    /// length integer as a `u32`.
438    ///
439    /// # Errors
440    ///
441    /// If `BinaryReader` has less than one or up to four bytes remaining, or
442    /// the integer is larger than 32 bits.
443    #[inline]
444    pub fn read_var_u32(&mut self) -> Result<u32> {
445        // Optimization for single byte i32.
446        let byte = self.read_u8()?;
447        if (byte & 0x80) == 0 {
448            Ok(u32::from(byte))
449        } else {
450            self.read_var_u32_big(byte)
451        }
452    }
453
454    fn read_var_u32_big(&mut self, byte: u8) -> Result<u32> {
455        let mut result = (byte & 0x7F) as u32;
456        let mut shift = 7;
457        loop {
458            let byte = self.read_u8()?;
459            result |= ((byte & 0x7F) as u32) << shift;
460            if shift >= 25 && (byte >> (32 - shift)) != 0 {
461                let msg = if byte & 0x80 != 0 {
462                    "invalid var_u32: integer representation too long"
463                } else {
464                    "invalid var_u32: integer too large"
465                };
466                // The continuation bit or unused bits are set.
467                return Err(BinaryReaderError::new(msg, self.original_position() - 1));
468            }
469            shift += 7;
470            if (byte & 0x80) == 0 {
471                break;
472            }
473        }
474        Ok(result)
475    }
476
477    /// Advances the `BinaryReader` up to four bytes to parse a variable
478    /// length integer as a `u64`.
479    ///
480    /// # Errors
481    ///
482    /// If `BinaryReader` has less than one or up to eight bytes remaining, or
483    /// the integer is larger than 64 bits.
484    #[inline]
485    pub fn read_var_u64(&mut self) -> Result<u64> {
486        // Optimization for single byte u64.
487        let byte = u64::from(self.read_u8()?);
488        if (byte & 0x80) == 0 {
489            Ok(byte)
490        } else {
491            self.read_var_u64_big(byte)
492        }
493    }
494
495    fn read_var_u64_big(&mut self, byte: u64) -> Result<u64> {
496        let mut result = byte & 0x7F;
497        let mut shift = 7;
498        loop {
499            let byte = u64::from(self.read_u8()?);
500            result |= (byte & 0x7F) << shift;
501            if shift >= 57 && (byte >> (64 - shift)) != 0 {
502                let msg = if byte & 0x80 != 0 {
503                    "invalid var_u64: integer representation too long"
504                } else {
505                    "invalid var_u64: integer too large"
506                };
507                // The continuation bit or unused bits are set.
508                return Err(BinaryReaderError::new(msg, self.original_position() - 1));
509            }
510            shift += 7;
511            if (byte & 0x80) == 0 {
512                break;
513            }
514        }
515        Ok(result)
516    }
517
518    /// Executes `f` to skip some data in this binary reader and then returns a
519    /// reader which will read the skipped data.
520    pub fn skip(&mut self, f: impl FnOnce(&mut Self) -> Result<()>) -> Result<Self> {
521        let start = self.position;
522        f(self)?;
523        let mut ret = self.clone();
524        ret.buffer = &self.buffer[start..self.position];
525        ret.position = 0;
526        ret.original_offset = self.original_offset + start;
527        Ok(ret)
528    }
529
530    /// Advances the `BinaryReader` past a WebAssembly string. This method does
531    /// not perform any utf-8 validation.
532    /// # Errors
533    /// If `BinaryReader` has less than four bytes, the string's length exceeds
534    /// the remaining bytes, or the string length
535    /// exceeds `limits::MAX_WASM_STRING_SIZE`.
536    pub fn skip_string(&mut self) -> Result<()> {
537        let len = self.read_var_u32()? as usize;
538        if len > MAX_WASM_STRING_SIZE {
539            return Err(BinaryReaderError::new(
540                "string size out of bounds",
541                self.original_position() - 1,
542            ));
543        }
544        self.ensure_has_bytes(len)?;
545        self.position += len;
546        Ok(())
547    }
548
549    /// Advances the `BinaryReader` up to four bytes to parse a variable
550    /// length integer as a `i32`.
551    /// # Errors
552    /// If `BinaryReader` has less than one or up to four bytes remaining, or
553    /// the integer is larger than 32 bits.
554    #[inline]
555    pub fn read_var_i32(&mut self) -> Result<i32> {
556        // Optimization for single byte i32.
557        let byte = self.read_u8()?;
558        if (byte & 0x80) == 0 {
559            Ok(((byte as i32) << 25) >> 25)
560        } else {
561            self.read_var_i32_big(byte)
562        }
563    }
564
565    fn read_var_i32_big(&mut self, byte: u8) -> Result<i32> {
566        let mut result = (byte & 0x7F) as i32;
567        let mut shift = 7;
568        loop {
569            let byte = self.read_u8()?;
570            result |= ((byte & 0x7F) as i32) << shift;
571            if shift >= 25 {
572                let continuation_bit = (byte & 0x80) != 0;
573                let sign_and_unused_bit = (byte << 1) as i8 >> (32 - shift);
574                if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
575                    let msg = if continuation_bit {
576                        "invalid var_i32: integer representation too long"
577                    } else {
578                        "invalid var_i32: integer too large"
579                    };
580                    return Err(BinaryReaderError::new(msg, self.original_position() - 1));
581                }
582                return Ok(result);
583            }
584            shift += 7;
585            if (byte & 0x80) == 0 {
586                break;
587            }
588        }
589        let ashift = 32 - shift;
590        Ok((result << ashift) >> ashift)
591    }
592
593    /// Advances the `BinaryReader` up to four bytes to parse a variable
594    /// length integer as a signed 33 bit integer, returned as a `i64`.
595    /// # Errors
596    /// If `BinaryReader` has less than one or up to five bytes remaining, or
597    /// the integer is larger than 33 bits.
598    pub fn read_var_s33(&mut self) -> Result<i64> {
599        // Optimization for single byte.
600        let byte = self.read_u8()?;
601        if (byte & 0x80) == 0 {
602            return Ok(((byte as i8) << 1) as i64 >> 1);
603        }
604
605        let mut result = (byte & 0x7F) as i64;
606        let mut shift = 7;
607        loop {
608            let byte = self.read_u8()?;
609            result |= ((byte & 0x7F) as i64) << shift;
610            if shift >= 25 {
611                let continuation_bit = (byte & 0x80) != 0;
612                let sign_and_unused_bit = (byte << 1) as i8 >> (33 - shift);
613                if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
614                    return Err(BinaryReaderError::new(
615                        "invalid var_s33: integer representation too long",
616                        self.original_position() - 1,
617                    ));
618                }
619                return Ok(result);
620            }
621            shift += 7;
622            if (byte & 0x80) == 0 {
623                break;
624            }
625        }
626        let ashift = 64 - shift;
627        Ok((result << ashift) >> ashift)
628    }
629
630    /// Advances the `BinaryReader` up to eight bytes to parse a variable
631    /// length integer as a 64 bit integer, returned as a `i64`.
632    /// # Errors
633    /// If `BinaryReader` has less than one or up to eight bytes remaining, or
634    /// the integer is larger than 64 bits.
635    pub fn read_var_i64(&mut self) -> Result<i64> {
636        let mut result: i64 = 0;
637        let mut shift = 0;
638        loop {
639            let byte = self.read_u8()?;
640            result |= i64::from(byte & 0x7F) << shift;
641            if shift >= 57 {
642                let continuation_bit = (byte & 0x80) != 0;
643                let sign_and_unused_bit = ((byte << 1) as i8) >> (64 - shift);
644                if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
645                    let msg = if continuation_bit {
646                        "invalid var_i64: integer representation too long"
647                    } else {
648                        "invalid var_i64: integer too large"
649                    };
650                    return Err(BinaryReaderError::new(msg, self.original_position() - 1));
651                }
652                return Ok(result);
653            }
654            shift += 7;
655            if (byte & 0x80) == 0 {
656                break;
657            }
658        }
659        let ashift = 64 - shift;
660        Ok((result << ashift) >> ashift)
661    }
662
663    /// Advances the `BinaryReader` four bytes to parse a 32 bit floating point
664    /// number, returned as `Ieee32`.
665    /// # Errors
666    /// If `BinaryReader` has less than four bytes remaining.
667    pub fn read_f32(&mut self) -> Result<Ieee32> {
668        let value = self.read_u32()?;
669        Ok(Ieee32(value))
670    }
671
672    /// Advances the `BinaryReader` eight bytes to parse a 64 bit floating point
673    /// number, returned as `Ieee64`.
674    /// # Errors
675    /// If `BinaryReader` has less than eight bytes remaining.
676    pub fn read_f64(&mut self) -> Result<Ieee64> {
677        let value = self.read_u64()?;
678        Ok(Ieee64(value))
679    }
680
681    /// (internal) Reads a fixed-size WebAssembly string from the module.
682    fn internal_read_string(&mut self, len: usize) -> Result<&'a str> {
683        let bytes = self.read_bytes(len)?;
684        str::from_utf8(bytes).map_err(|_| {
685            BinaryReaderError::new("malformed UTF-8 encoding", self.original_position() - 1)
686        })
687    }
688
689    /// Reads a WebAssembly string from the module.
690    ///
691    /// # Errors
692    ///
693    /// If `BinaryReader` has less than up to four bytes remaining, the string's
694    /// length exceeds the remaining bytes, the string's length exceeds
695    /// `limits::MAX_WASM_STRING_SIZE`, or the string contains invalid utf-8.
696    pub fn read_string(&mut self) -> Result<&'a str> {
697        let len = self.read_var_u32()? as usize;
698        if len > MAX_WASM_STRING_SIZE {
699            return Err(BinaryReaderError::new(
700                "string size out of bounds",
701                self.original_position() - 1,
702            ));
703        }
704        return self.internal_read_string(len);
705    }
706
707    /// Reads a unlimited WebAssembly string from the module.
708    ///
709    /// Note that this is similar to [`BinaryReader::read_string`] except that
710    /// it will not limit the size of the returned string by
711    /// `limits::MAX_WASM_STRING_SIZE`.
712    pub fn read_unlimited_string(&mut self) -> Result<&'a str> {
713        let len = self.read_var_u32()? as usize;
714        return self.internal_read_string(len);
715    }
716
717    #[cold]
718    pub(crate) fn invalid_leading_byte<T>(&self, byte: u8, desc: &str) -> Result<T> {
719        Err(Self::invalid_leading_byte_error(
720            byte,
721            desc,
722            self.original_position() - 1,
723        ))
724    }
725
726    pub(crate) fn invalid_leading_byte_error(
727        byte: u8,
728        desc: &str,
729        offset: usize,
730    ) -> BinaryReaderError {
731        format_err!(offset, "invalid leading byte (0x{byte:x}) for {desc}")
732    }
733
734    pub(crate) fn peek(&self) -> Result<u8> {
735        self.ensure_has_byte()?;
736        Ok(self.buffer[self.position])
737    }
738
739    pub(crate) fn read_block_type(&mut self) -> Result<BlockType> {
740        let b = self.peek()?;
741
742        // Block types are encoded as either 0x40, a `valtype`, or `s33`. All
743        // current `valtype` encodings are negative numbers when encoded with
744        // sleb128, but it's also required that valtype encodings are in their
745        // canonical form. For example an overlong encoding of -1 as `0xff 0x7f`
746        // is not valid and it is required to be `0x7f`. This means that we
747        // can't simply match on the `s33` that pops out below since reading the
748        // whole `s33` might read an overlong encoding.
749        //
750        // To test for this the first byte `b` is inspected. The highest bit,
751        // the continuation bit in LEB128 encoding, must be clear. The next bit,
752        // the sign bit, must be set to indicate that the number is negative. If
753        // these two conditions hold then we're guaranteed that this is a
754        // negative number.
755        //
756        // After this a value type is read directly instead of looking for an
757        // indexed value type.
758        if b & 0x80 == 0 && b & 0x40 != 0 {
759            if b == 0x40 {
760                self.position += 1;
761                return Ok(BlockType::Empty);
762            }
763            return Ok(BlockType::Type(self.read()?));
764        }
765
766        // Not empty or a singular type, so read the function type index
767        let idx = self.read_var_s33()?;
768        match u32::try_from(idx) {
769            Ok(idx) => Ok(BlockType::FuncType(idx)),
770            Err(_) => {
771                return Err(BinaryReaderError::new(
772                    "invalid function type",
773                    self.original_position(),
774                ));
775            }
776        }
777    }
778
779    /// Returns whether there is an `end` opcode followed by eof remaining in
780    /// this reader.
781    pub fn is_end_then_eof(&self) -> bool {
782        self.remaining_buffer() == &[0x0b]
783    }
784
785    pub(crate) fn read_header_version(&mut self) -> Result<u32> {
786        let magic_number = self.read_bytes(4)?;
787        if magic_number != WASM_MAGIC_NUMBER {
788            return Err(BinaryReaderError::new(
789                format!(
790                    "magic header not detected: bad magic number - expected={WASM_MAGIC_NUMBER:#x?} actual={magic_number:#x?}"
791                ),
792                self.original_position() - 4,
793            ));
794        }
795        self.read_u32()
796    }
797}
798
799// See documentation on `BinaryReader::features` for more on what's going on
800// here.
801macro_rules! define_feature_accessor {
802    ($feature:ident = $default:expr) => {
803        impl BinaryReader<'_> {
804            #[inline]
805            #[allow(dead_code)]
806            pub(crate) fn $feature(&self) -> bool {
807                #[cfg(feature = "features")]
808                {
809                    self.features.$feature()
810                }
811                #[cfg(not(feature = "features"))]
812                {
813                    true
814                }
815            }
816        }
817    };
818}
819
820super::features::foreach_wasm_feature!(define_feature_accessor);
821
822/// Iterator returned from [`BinaryReader::read_iter`].
823pub struct BinaryReaderIter<'a, 'me, T: FromReader<'a>> {
824    remaining: usize,
825    pub(crate) reader: &'me mut BinaryReader<'a>,
826    _marker: marker::PhantomData<T>,
827}
828
829impl<'a, T> Iterator for BinaryReaderIter<'a, '_, T>
830where
831    T: FromReader<'a>,
832{
833    type Item = Result<T>;
834
835    fn next(&mut self) -> Option<Result<T>> {
836        if self.remaining == 0 {
837            None
838        } else {
839            let ret = self.reader.read::<T>();
840            if ret.is_err() {
841                self.remaining = 0;
842            } else {
843                self.remaining -= 1;
844            }
845            Some(ret)
846        }
847    }
848
849    fn size_hint(&self) -> (usize, Option<usize>) {
850        (self.remaining, Some(self.remaining))
851    }
852}
853
854impl<'a, T> Drop for BinaryReaderIter<'a, '_, T>
855where
856    T: FromReader<'a>,
857{
858    fn drop(&mut self) {
859        while self.next().is_some() {
860            // ...
861        }
862    }
863}
864
865impl<'a> BinaryReader<'a> {
866    /// Function that must be called after the last opcode in an expression (instruction sequence)
867    /// has been processed. Returns an error if there is extra data after the operators.
868    pub fn finish_expression(&self, stack: &impl FrameStack) -> Result<()> {
869        if stack.current_frame().is_some() {
870            bail!(
871                self.original_position(),
872                "control frames remain at end of function body or expression"
873            );
874        }
875        if !self.eof() {
876            bail!(
877                self.original_position(),
878                "unexpected data at the end of operators"
879            );
880        }
881        Ok(())
882    }
883
884    #[inline]
885    fn expect_frame(&mut self, stack: &impl FrameStack, k: FrameKind, found: &str) -> Result<()> {
886        if stack.current_frame() == Some(k) {
887            return Ok(());
888        }
889        bail!(
890            self.original_position(),
891            "`{}` found outside `{:?}` block",
892            found,
893            k
894        );
895    }
896
897    /// Visit the next available operator with the specified [`VisitOperator`] instance
898    /// that is also a [`FrameStack`].
899    ///
900    /// See the documentation for [`OperatorsReader::visit_operator`] for a version that
901    /// does not require the visitor to implement [`FrameStack`].
902    pub fn visit_operator<T>(&mut self, visitor: &mut T) -> Result<<T as VisitOperator<'a>>::Output>
903    where
904        T: VisitOperator<'a> + FrameStack,
905    {
906        if visitor.current_frame().is_none() {
907            bail!(
908                self.original_position(),
909                "operators remaining after end of function body or expression"
910            );
911        }
912        let pos = self.original_position();
913        let code = self.read_u8()?;
914        Ok(match code {
915            0x00 => visitor.visit_unreachable(),
916            0x01 => visitor.visit_nop(),
917            0x02 => visitor.visit_block(self.read_block_type()?),
918            0x03 => visitor.visit_loop(self.read_block_type()?),
919            0x04 => visitor.visit_if(self.read_block_type()?),
920            0x05 => {
921                self.expect_frame(visitor, FrameKind::If, "else")?;
922                visitor.visit_else()
923            }
924            0x06 => {
925                if !self.legacy_exceptions() {
926                    bail!(
927                        pos,
928                        "legacy_exceptions feature required for try instruction"
929                    );
930                }
931                visitor.visit_try(self.read_block_type()?)
932            }
933            0x07 => {
934                if !self.legacy_exceptions() {
935                    bail!(
936                        pos,
937                        "legacy_exceptions feature required for catch instruction"
938                    );
939                }
940                match self.expect_frame(visitor, FrameKind::LegacyCatch, "catch") {
941                    Ok(()) => (),
942                    Err(_) => self.expect_frame(visitor, FrameKind::LegacyTry, "catch")?,
943                }
944                visitor.visit_catch(self.read_var_u32()?)
945            }
946            0x08 => visitor.visit_throw(self.read_var_u32()?),
947            0x09 => visitor.visit_rethrow(self.read_var_u32()?),
948            0x0a => visitor.visit_throw_ref(),
949            0x0b => visitor.visit_end(),
950            0x0c => visitor.visit_br(self.read_var_u32()?),
951            0x0d => visitor.visit_br_if(self.read_var_u32()?),
952            0x0e => visitor.visit_br_table(self.read_br_table()?),
953            0x0f => visitor.visit_return(),
954            0x10 => visitor.visit_call(self.read_var_u32()?),
955            0x11 => {
956                let index = self.read_var_u32()?;
957                let table = self.read_call_indirect_table_immediate()?;
958                visitor.visit_call_indirect(index, table)
959            }
960            0x12 => visitor.visit_return_call(self.read_var_u32()?),
961            0x13 => visitor.visit_return_call_indirect(self.read_var_u32()?, self.read_var_u32()?),
962            0x14 => visitor.visit_call_ref(self.read()?),
963            0x15 => visitor.visit_return_call_ref(self.read()?),
964            0x18 => {
965                self.expect_frame(visitor, FrameKind::LegacyTry, "delegate")?;
966                visitor.visit_delegate(self.read_var_u32()?)
967            }
968            0x19 => {
969                if !self.legacy_exceptions() {
970                    bail!(
971                        pos,
972                        "legacy_exceptions feature required for catch_all instruction"
973                    );
974                }
975                match self.expect_frame(visitor, FrameKind::LegacyCatch, "catch_all") {
976                    Ok(()) => (),
977                    Err(_) => self.expect_frame(visitor, FrameKind::LegacyTry, "catch_all")?,
978                }
979                visitor.visit_catch_all()
980            }
981            0x1a => visitor.visit_drop(),
982            0x1b => visitor.visit_select(),
983            0x1c => {
984                let result_count = self.read_size(MAX_WASM_SELECT_RESULT_SIZE, "select types")?;
985                if result_count == 1 {
986                    visitor.visit_typed_select(self.read()?)
987                } else {
988                    let mut results = Vec::new();
989                    results.reserve_exact(result_count);
990                    for _ in 0..result_count {
991                        results.push(self.read()?);
992                    }
993                    visitor.visit_typed_select_multi(results)
994                }
995            }
996            0x1f => visitor.visit_try_table(self.read()?),
997
998            0x20 => visitor.visit_local_get(self.read_var_u32()?),
999            0x21 => visitor.visit_local_set(self.read_var_u32()?),
1000            0x22 => visitor.visit_local_tee(self.read_var_u32()?),
1001            0x23 => visitor.visit_global_get(self.read_var_u32()?),
1002            0x24 => visitor.visit_global_set(self.read_var_u32()?),
1003            0x25 => visitor.visit_table_get(self.read_var_u32()?),
1004            0x26 => visitor.visit_table_set(self.read_var_u32()?),
1005
1006            0x28 => visitor.visit_i32_load(self.read_memarg(2)?),
1007            0x29 => visitor.visit_i64_load(self.read_memarg(3)?),
1008            0x2a => visitor.visit_f32_load(self.read_memarg(2)?),
1009            0x2b => visitor.visit_f64_load(self.read_memarg(3)?),
1010            0x2c => visitor.visit_i32_load8_s(self.read_memarg(0)?),
1011            0x2d => visitor.visit_i32_load8_u(self.read_memarg(0)?),
1012            0x2e => visitor.visit_i32_load16_s(self.read_memarg(1)?),
1013            0x2f => visitor.visit_i32_load16_u(self.read_memarg(1)?),
1014            0x30 => visitor.visit_i64_load8_s(self.read_memarg(0)?),
1015            0x31 => visitor.visit_i64_load8_u(self.read_memarg(0)?),
1016            0x32 => visitor.visit_i64_load16_s(self.read_memarg(1)?),
1017            0x33 => visitor.visit_i64_load16_u(self.read_memarg(1)?),
1018            0x34 => visitor.visit_i64_load32_s(self.read_memarg(2)?),
1019            0x35 => visitor.visit_i64_load32_u(self.read_memarg(2)?),
1020            0x36 => visitor.visit_i32_store(self.read_memarg(2)?),
1021            0x37 => visitor.visit_i64_store(self.read_memarg(3)?),
1022            0x38 => visitor.visit_f32_store(self.read_memarg(2)?),
1023            0x39 => visitor.visit_f64_store(self.read_memarg(3)?),
1024            0x3a => visitor.visit_i32_store8(self.read_memarg(0)?),
1025            0x3b => visitor.visit_i32_store16(self.read_memarg(1)?),
1026            0x3c => visitor.visit_i64_store8(self.read_memarg(0)?),
1027            0x3d => visitor.visit_i64_store16(self.read_memarg(1)?),
1028            0x3e => visitor.visit_i64_store32(self.read_memarg(2)?),
1029            0x3f => {
1030                let mem = self.read_memory_index_or_zero_if_not_multi_memory()?;
1031                visitor.visit_memory_size(mem)
1032            }
1033            0x40 => {
1034                let mem = self.read_memory_index_or_zero_if_not_multi_memory()?;
1035                visitor.visit_memory_grow(mem)
1036            }
1037
1038            0x41 => visitor.visit_i32_const(self.read_var_i32()?),
1039            0x42 => visitor.visit_i64_const(self.read_var_i64()?),
1040            0x43 => visitor.visit_f32_const(self.read_f32()?),
1041            0x44 => visitor.visit_f64_const(self.read_f64()?),
1042
1043            0x45 => visitor.visit_i32_eqz(),
1044            0x46 => visitor.visit_i32_eq(),
1045            0x47 => visitor.visit_i32_ne(),
1046            0x48 => visitor.visit_i32_lt_s(),
1047            0x49 => visitor.visit_i32_lt_u(),
1048            0x4a => visitor.visit_i32_gt_s(),
1049            0x4b => visitor.visit_i32_gt_u(),
1050            0x4c => visitor.visit_i32_le_s(),
1051            0x4d => visitor.visit_i32_le_u(),
1052            0x4e => visitor.visit_i32_ge_s(),
1053            0x4f => visitor.visit_i32_ge_u(),
1054            0x50 => visitor.visit_i64_eqz(),
1055            0x51 => visitor.visit_i64_eq(),
1056            0x52 => visitor.visit_i64_ne(),
1057            0x53 => visitor.visit_i64_lt_s(),
1058            0x54 => visitor.visit_i64_lt_u(),
1059            0x55 => visitor.visit_i64_gt_s(),
1060            0x56 => visitor.visit_i64_gt_u(),
1061            0x57 => visitor.visit_i64_le_s(),
1062            0x58 => visitor.visit_i64_le_u(),
1063            0x59 => visitor.visit_i64_ge_s(),
1064            0x5a => visitor.visit_i64_ge_u(),
1065            0x5b => visitor.visit_f32_eq(),
1066            0x5c => visitor.visit_f32_ne(),
1067            0x5d => visitor.visit_f32_lt(),
1068            0x5e => visitor.visit_f32_gt(),
1069            0x5f => visitor.visit_f32_le(),
1070            0x60 => visitor.visit_f32_ge(),
1071            0x61 => visitor.visit_f64_eq(),
1072            0x62 => visitor.visit_f64_ne(),
1073            0x63 => visitor.visit_f64_lt(),
1074            0x64 => visitor.visit_f64_gt(),
1075            0x65 => visitor.visit_f64_le(),
1076            0x66 => visitor.visit_f64_ge(),
1077            0x67 => visitor.visit_i32_clz(),
1078            0x68 => visitor.visit_i32_ctz(),
1079            0x69 => visitor.visit_i32_popcnt(),
1080            0x6a => visitor.visit_i32_add(),
1081            0x6b => visitor.visit_i32_sub(),
1082            0x6c => visitor.visit_i32_mul(),
1083            0x6d => visitor.visit_i32_div_s(),
1084            0x6e => visitor.visit_i32_div_u(),
1085            0x6f => visitor.visit_i32_rem_s(),
1086            0x70 => visitor.visit_i32_rem_u(),
1087            0x71 => visitor.visit_i32_and(),
1088            0x72 => visitor.visit_i32_or(),
1089            0x73 => visitor.visit_i32_xor(),
1090            0x74 => visitor.visit_i32_shl(),
1091            0x75 => visitor.visit_i32_shr_s(),
1092            0x76 => visitor.visit_i32_shr_u(),
1093            0x77 => visitor.visit_i32_rotl(),
1094            0x78 => visitor.visit_i32_rotr(),
1095            0x79 => visitor.visit_i64_clz(),
1096            0x7a => visitor.visit_i64_ctz(),
1097            0x7b => visitor.visit_i64_popcnt(),
1098            0x7c => visitor.visit_i64_add(),
1099            0x7d => visitor.visit_i64_sub(),
1100            0x7e => visitor.visit_i64_mul(),
1101            0x7f => visitor.visit_i64_div_s(),
1102            0x80 => visitor.visit_i64_div_u(),
1103            0x81 => visitor.visit_i64_rem_s(),
1104            0x82 => visitor.visit_i64_rem_u(),
1105            0x83 => visitor.visit_i64_and(),
1106            0x84 => visitor.visit_i64_or(),
1107            0x85 => visitor.visit_i64_xor(),
1108            0x86 => visitor.visit_i64_shl(),
1109            0x87 => visitor.visit_i64_shr_s(),
1110            0x88 => visitor.visit_i64_shr_u(),
1111            0x89 => visitor.visit_i64_rotl(),
1112            0x8a => visitor.visit_i64_rotr(),
1113            0x8b => visitor.visit_f32_abs(),
1114            0x8c => visitor.visit_f32_neg(),
1115            0x8d => visitor.visit_f32_ceil(),
1116            0x8e => visitor.visit_f32_floor(),
1117            0x8f => visitor.visit_f32_trunc(),
1118            0x90 => visitor.visit_f32_nearest(),
1119            0x91 => visitor.visit_f32_sqrt(),
1120            0x92 => visitor.visit_f32_add(),
1121            0x93 => visitor.visit_f32_sub(),
1122            0x94 => visitor.visit_f32_mul(),
1123            0x95 => visitor.visit_f32_div(),
1124            0x96 => visitor.visit_f32_min(),
1125            0x97 => visitor.visit_f32_max(),
1126            0x98 => visitor.visit_f32_copysign(),
1127            0x99 => visitor.visit_f64_abs(),
1128            0x9a => visitor.visit_f64_neg(),
1129            0x9b => visitor.visit_f64_ceil(),
1130            0x9c => visitor.visit_f64_floor(),
1131            0x9d => visitor.visit_f64_trunc(),
1132            0x9e => visitor.visit_f64_nearest(),
1133            0x9f => visitor.visit_f64_sqrt(),
1134            0xa0 => visitor.visit_f64_add(),
1135            0xa1 => visitor.visit_f64_sub(),
1136            0xa2 => visitor.visit_f64_mul(),
1137            0xa3 => visitor.visit_f64_div(),
1138            0xa4 => visitor.visit_f64_min(),
1139            0xa5 => visitor.visit_f64_max(),
1140            0xa6 => visitor.visit_f64_copysign(),
1141            0xa7 => visitor.visit_i32_wrap_i64(),
1142            0xa8 => visitor.visit_i32_trunc_f32_s(),
1143            0xa9 => visitor.visit_i32_trunc_f32_u(),
1144            0xaa => visitor.visit_i32_trunc_f64_s(),
1145            0xab => visitor.visit_i32_trunc_f64_u(),
1146            0xac => visitor.visit_i64_extend_i32_s(),
1147            0xad => visitor.visit_i64_extend_i32_u(),
1148            0xae => visitor.visit_i64_trunc_f32_s(),
1149            0xaf => visitor.visit_i64_trunc_f32_u(),
1150            0xb0 => visitor.visit_i64_trunc_f64_s(),
1151            0xb1 => visitor.visit_i64_trunc_f64_u(),
1152            0xb2 => visitor.visit_f32_convert_i32_s(),
1153            0xb3 => visitor.visit_f32_convert_i32_u(),
1154            0xb4 => visitor.visit_f32_convert_i64_s(),
1155            0xb5 => visitor.visit_f32_convert_i64_u(),
1156            0xb6 => visitor.visit_f32_demote_f64(),
1157            0xb7 => visitor.visit_f64_convert_i32_s(),
1158            0xb8 => visitor.visit_f64_convert_i32_u(),
1159            0xb9 => visitor.visit_f64_convert_i64_s(),
1160            0xba => visitor.visit_f64_convert_i64_u(),
1161            0xbb => visitor.visit_f64_promote_f32(),
1162            0xbc => visitor.visit_i32_reinterpret_f32(),
1163            0xbd => visitor.visit_i64_reinterpret_f64(),
1164            0xbe => visitor.visit_f32_reinterpret_i32(),
1165            0xbf => visitor.visit_f64_reinterpret_i64(),
1166
1167            0xc0 => visitor.visit_i32_extend8_s(),
1168            0xc1 => visitor.visit_i32_extend16_s(),
1169            0xc2 => visitor.visit_i64_extend8_s(),
1170            0xc3 => visitor.visit_i64_extend16_s(),
1171            0xc4 => visitor.visit_i64_extend32_s(),
1172
1173            0xd0 => visitor.visit_ref_null(self.read()?),
1174            0xd1 => visitor.visit_ref_is_null(),
1175            0xd2 => visitor.visit_ref_func(self.read_var_u32()?),
1176            0xd3 => visitor.visit_ref_eq(),
1177            0xd4 => visitor.visit_ref_as_non_null(),
1178            0xd5 => visitor.visit_br_on_null(self.read_var_u32()?),
1179            0xd6 => visitor.visit_br_on_non_null(self.read_var_u32()?),
1180
1181            0xe0 => visitor.visit_cont_new(self.read_var_u32()?),
1182            0xe1 => visitor.visit_cont_bind(self.read_var_u32()?, self.read_var_u32()?),
1183            0xe2 => visitor.visit_suspend(self.read_var_u32()?),
1184            0xe3 => visitor.visit_resume(self.read_var_u32()?, self.read()?),
1185            0xe4 => {
1186                visitor.visit_resume_throw(self.read_var_u32()?, self.read_var_u32()?, self.read()?)
1187            }
1188            0xe5 => visitor.visit_switch(self.read_var_u32()?, self.read_var_u32()?),
1189
1190            0xfb => self.visit_0xfb_operator(pos, visitor)?,
1191            0xfc => self.visit_0xfc_operator(pos, visitor)?,
1192            0xfd => {
1193                #[cfg(feature = "simd")]
1194                if let Some(mut visitor) = visitor.simd_visitor() {
1195                    return self.visit_0xfd_operator(pos, &mut visitor);
1196                }
1197                bail!(pos, "unexpected SIMD opcode: 0x{code:x}")
1198            }
1199            0xfe => self.visit_0xfe_operator(pos, visitor)?,
1200
1201            _ => bail!(pos, "illegal opcode: 0x{code:x}"),
1202        })
1203    }
1204
1205    fn visit_0xfb_operator<T>(
1206        &mut self,
1207        pos: usize,
1208        visitor: &mut T,
1209    ) -> Result<<T as VisitOperator<'a>>::Output>
1210    where
1211        T: VisitOperator<'a>,
1212    {
1213        let code = self.read_var_u32()?;
1214        Ok(match code {
1215            0x0 => {
1216                let type_index = self.read_var_u32()?;
1217                visitor.visit_struct_new(type_index)
1218            }
1219            0x01 => {
1220                let type_index = self.read_var_u32()?;
1221                visitor.visit_struct_new_default(type_index)
1222            }
1223            0x02 => {
1224                let type_index = self.read_var_u32()?;
1225                let field_index = self.read_var_u32()?;
1226                visitor.visit_struct_get(type_index, field_index)
1227            }
1228            0x03 => {
1229                let type_index = self.read_var_u32()?;
1230                let field_index = self.read_var_u32()?;
1231                visitor.visit_struct_get_s(type_index, field_index)
1232            }
1233            0x04 => {
1234                let type_index = self.read_var_u32()?;
1235                let field_index = self.read_var_u32()?;
1236                visitor.visit_struct_get_u(type_index, field_index)
1237            }
1238            0x05 => {
1239                let type_index = self.read_var_u32()?;
1240                let field_index = self.read_var_u32()?;
1241                visitor.visit_struct_set(type_index, field_index)
1242            }
1243            0x06 => {
1244                let type_index = self.read_var_u32()?;
1245                visitor.visit_array_new(type_index)
1246            }
1247            0x07 => {
1248                let type_index = self.read_var_u32()?;
1249                visitor.visit_array_new_default(type_index)
1250            }
1251            0x08 => {
1252                let type_index = self.read_var_u32()?;
1253                let n = self.read_var_u32()?;
1254                visitor.visit_array_new_fixed(type_index, n)
1255            }
1256            0x09 => {
1257                let type_index = self.read_var_u32()?;
1258                let data_index = self.read_var_u32()?;
1259                visitor.visit_array_new_data(type_index, data_index)
1260            }
1261            0x0a => {
1262                let type_index = self.read_var_u32()?;
1263                let elem_index = self.read_var_u32()?;
1264                visitor.visit_array_new_elem(type_index, elem_index)
1265            }
1266            0x0b => {
1267                let type_index = self.read_var_u32()?;
1268                visitor.visit_array_get(type_index)
1269            }
1270            0x0c => {
1271                let type_index = self.read_var_u32()?;
1272                visitor.visit_array_get_s(type_index)
1273            }
1274            0x0d => {
1275                let type_index = self.read_var_u32()?;
1276                visitor.visit_array_get_u(type_index)
1277            }
1278            0x0e => {
1279                let type_index = self.read_var_u32()?;
1280                visitor.visit_array_set(type_index)
1281            }
1282            0x0f => visitor.visit_array_len(),
1283            0x10 => {
1284                let type_index = self.read_var_u32()?;
1285                visitor.visit_array_fill(type_index)
1286            }
1287            0x11 => {
1288                let type_index_dst = self.read_var_u32()?;
1289                let type_index_src = self.read_var_u32()?;
1290                visitor.visit_array_copy(type_index_dst, type_index_src)
1291            }
1292            0x12 => {
1293                let type_index = self.read_var_u32()?;
1294                let data_index = self.read_var_u32()?;
1295                visitor.visit_array_init_data(type_index, data_index)
1296            }
1297            0x13 => {
1298                let type_index = self.read_var_u32()?;
1299                let elem_index = self.read_var_u32()?;
1300                visitor.visit_array_init_elem(type_index, elem_index)
1301            }
1302            0x14 => visitor.visit_ref_test_non_null(self.read()?),
1303            0x15 => visitor.visit_ref_test_nullable(self.read()?),
1304            0x16 => visitor.visit_ref_cast_non_null(self.read()?),
1305            0x17 => visitor.visit_ref_cast_nullable(self.read()?),
1306            0x18 => {
1307                let pos = self.original_position();
1308                let cast_flags = self.read_u8()?;
1309                let relative_depth = self.read_var_u32()?;
1310                let (from_type_nullable, to_type_nullable) = match cast_flags {
1311                    0b00 => (false, false),
1312                    0b01 => (true, false),
1313                    0b10 => (false, true),
1314                    0b11 => (true, true),
1315                    _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"),
1316                };
1317                let from_heap_type = self.read()?;
1318                let from_ref_type =
1319                    RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| {
1320                        format_err!(pos, "implementation error: type index too large")
1321                    })?;
1322                let to_heap_type = self.read()?;
1323                let to_ref_type =
1324                    RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| {
1325                        format_err!(pos, "implementation error: type index too large")
1326                    })?;
1327                visitor.visit_br_on_cast(relative_depth, from_ref_type, to_ref_type)
1328            }
1329            0x19 => {
1330                let pos = self.original_position();
1331                let cast_flags = self.read_u8()?;
1332                let relative_depth = self.read_var_u32()?;
1333                let (from_type_nullable, to_type_nullable) = match cast_flags {
1334                    0 => (false, false),
1335                    1 => (true, false),
1336                    2 => (false, true),
1337                    3 => (true, true),
1338                    _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"),
1339                };
1340                let from_heap_type = self.read()?;
1341                let from_ref_type =
1342                    RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| {
1343                        format_err!(pos, "implementation error: type index too large")
1344                    })?;
1345                let to_heap_type = self.read()?;
1346                let to_ref_type =
1347                    RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| {
1348                        format_err!(pos, "implementation error: type index too large")
1349                    })?;
1350                visitor.visit_br_on_cast_fail(relative_depth, from_ref_type, to_ref_type)
1351            }
1352
1353            0x1a => visitor.visit_any_convert_extern(),
1354            0x1b => visitor.visit_extern_convert_any(),
1355
1356            0x1c => visitor.visit_ref_i31(),
1357            0x1d => visitor.visit_i31_get_s(),
1358            0x1e => visitor.visit_i31_get_u(),
1359
1360            _ => bail!(pos, "unknown 0xfb subopcode: 0x{code:x}"),
1361        })
1362    }
1363
1364    fn visit_0xfc_operator<T>(
1365        &mut self,
1366        pos: usize,
1367        visitor: &mut T,
1368    ) -> Result<<T as VisitOperator<'a>>::Output>
1369    where
1370        T: VisitOperator<'a>,
1371    {
1372        let code = self.read_var_u32()?;
1373        Ok(match code {
1374            0x00 => visitor.visit_i32_trunc_sat_f32_s(),
1375            0x01 => visitor.visit_i32_trunc_sat_f32_u(),
1376            0x02 => visitor.visit_i32_trunc_sat_f64_s(),
1377            0x03 => visitor.visit_i32_trunc_sat_f64_u(),
1378            0x04 => visitor.visit_i64_trunc_sat_f32_s(),
1379            0x05 => visitor.visit_i64_trunc_sat_f32_u(),
1380            0x06 => visitor.visit_i64_trunc_sat_f64_s(),
1381            0x07 => visitor.visit_i64_trunc_sat_f64_u(),
1382
1383            0x08 => {
1384                let segment = self.read_var_u32()?;
1385                let mem = self.read_var_u32()?;
1386                visitor.visit_memory_init(segment, mem)
1387            }
1388            0x09 => {
1389                let segment = self.read_var_u32()?;
1390                visitor.visit_data_drop(segment)
1391            }
1392            0x0a => {
1393                let dst = self.read_var_u32()?;
1394                let src = self.read_var_u32()?;
1395                visitor.visit_memory_copy(dst, src)
1396            }
1397            0x0b => {
1398                let mem = self.read_var_u32()?;
1399                visitor.visit_memory_fill(mem)
1400            }
1401            0x0c => {
1402                let segment = self.read_var_u32()?;
1403                let table = self.read_var_u32()?;
1404                visitor.visit_table_init(segment, table)
1405            }
1406            0x0d => {
1407                let segment = self.read_var_u32()?;
1408                visitor.visit_elem_drop(segment)
1409            }
1410            0x0e => {
1411                let dst_table = self.read_var_u32()?;
1412                let src_table = self.read_var_u32()?;
1413                visitor.visit_table_copy(dst_table, src_table)
1414            }
1415
1416            0x0f => {
1417                let table = self.read_var_u32()?;
1418                visitor.visit_table_grow(table)
1419            }
1420            0x10 => {
1421                let table = self.read_var_u32()?;
1422                visitor.visit_table_size(table)
1423            }
1424
1425            0x11 => {
1426                let table = self.read_var_u32()?;
1427                visitor.visit_table_fill(table)
1428            }
1429
1430            0x12 => {
1431                let mem = self.read_var_u32()?;
1432                visitor.visit_memory_discard(mem)
1433            }
1434
1435            0x13 => visitor.visit_i64_add128(),
1436            0x14 => visitor.visit_i64_sub128(),
1437            0x15 => visitor.visit_i64_mul_wide_s(),
1438            0x16 => visitor.visit_i64_mul_wide_u(),
1439
1440            _ => bail!(pos, "unknown 0xfc subopcode: 0x{code:x}"),
1441        })
1442    }
1443
1444    #[cfg(feature = "simd")]
1445    pub(super) fn visit_0xfd_operator<T>(
1446        &mut self,
1447        pos: usize,
1448        visitor: &mut T,
1449    ) -> Result<<T as VisitOperator<'a>>::Output>
1450    where
1451        T: VisitSimdOperator<'a>,
1452    {
1453        let code = self.read_var_u32()?;
1454        Ok(match code {
1455            0x00 => visitor.visit_v128_load(self.read_memarg(4)?),
1456            0x01 => visitor.visit_v128_load8x8_s(self.read_memarg(3)?),
1457            0x02 => visitor.visit_v128_load8x8_u(self.read_memarg(3)?),
1458            0x03 => visitor.visit_v128_load16x4_s(self.read_memarg(3)?),
1459            0x04 => visitor.visit_v128_load16x4_u(self.read_memarg(3)?),
1460            0x05 => visitor.visit_v128_load32x2_s(self.read_memarg(3)?),
1461            0x06 => visitor.visit_v128_load32x2_u(self.read_memarg(3)?),
1462            0x07 => visitor.visit_v128_load8_splat(self.read_memarg(0)?),
1463            0x08 => visitor.visit_v128_load16_splat(self.read_memarg(1)?),
1464            0x09 => visitor.visit_v128_load32_splat(self.read_memarg(2)?),
1465            0x0a => visitor.visit_v128_load64_splat(self.read_memarg(3)?),
1466
1467            0x0b => visitor.visit_v128_store(self.read_memarg(4)?),
1468            0x0c => visitor.visit_v128_const(self.read_v128()?),
1469            0x0d => {
1470                let mut lanes: [u8; 16] = [0; 16];
1471                for lane in &mut lanes {
1472                    *lane = self.read_lane_index()?
1473                }
1474                visitor.visit_i8x16_shuffle(lanes)
1475            }
1476
1477            0x0e => visitor.visit_i8x16_swizzle(),
1478            0x0f => visitor.visit_i8x16_splat(),
1479            0x10 => visitor.visit_i16x8_splat(),
1480            0x11 => visitor.visit_i32x4_splat(),
1481            0x12 => visitor.visit_i64x2_splat(),
1482            0x13 => visitor.visit_f32x4_splat(),
1483            0x14 => visitor.visit_f64x2_splat(),
1484
1485            0x15 => visitor.visit_i8x16_extract_lane_s(self.read_lane_index()?),
1486            0x16 => visitor.visit_i8x16_extract_lane_u(self.read_lane_index()?),
1487            0x17 => visitor.visit_i8x16_replace_lane(self.read_lane_index()?),
1488            0x18 => visitor.visit_i16x8_extract_lane_s(self.read_lane_index()?),
1489            0x19 => visitor.visit_i16x8_extract_lane_u(self.read_lane_index()?),
1490            0x1a => visitor.visit_i16x8_replace_lane(self.read_lane_index()?),
1491            0x1b => visitor.visit_i32x4_extract_lane(self.read_lane_index()?),
1492
1493            0x1c => visitor.visit_i32x4_replace_lane(self.read_lane_index()?),
1494            0x1d => visitor.visit_i64x2_extract_lane(self.read_lane_index()?),
1495            0x1e => visitor.visit_i64x2_replace_lane(self.read_lane_index()?),
1496            0x1f => visitor.visit_f32x4_extract_lane(self.read_lane_index()?),
1497            0x20 => visitor.visit_f32x4_replace_lane(self.read_lane_index()?),
1498            0x21 => visitor.visit_f64x2_extract_lane(self.read_lane_index()?),
1499            0x22 => visitor.visit_f64x2_replace_lane(self.read_lane_index()?),
1500
1501            0x23 => visitor.visit_i8x16_eq(),
1502            0x24 => visitor.visit_i8x16_ne(),
1503            0x25 => visitor.visit_i8x16_lt_s(),
1504            0x26 => visitor.visit_i8x16_lt_u(),
1505            0x27 => visitor.visit_i8x16_gt_s(),
1506            0x28 => visitor.visit_i8x16_gt_u(),
1507            0x29 => visitor.visit_i8x16_le_s(),
1508            0x2a => visitor.visit_i8x16_le_u(),
1509            0x2b => visitor.visit_i8x16_ge_s(),
1510            0x2c => visitor.visit_i8x16_ge_u(),
1511            0x2d => visitor.visit_i16x8_eq(),
1512            0x2e => visitor.visit_i16x8_ne(),
1513            0x2f => visitor.visit_i16x8_lt_s(),
1514            0x30 => visitor.visit_i16x8_lt_u(),
1515            0x31 => visitor.visit_i16x8_gt_s(),
1516            0x32 => visitor.visit_i16x8_gt_u(),
1517            0x33 => visitor.visit_i16x8_le_s(),
1518            0x34 => visitor.visit_i16x8_le_u(),
1519            0x35 => visitor.visit_i16x8_ge_s(),
1520            0x36 => visitor.visit_i16x8_ge_u(),
1521            0x37 => visitor.visit_i32x4_eq(),
1522            0x38 => visitor.visit_i32x4_ne(),
1523            0x39 => visitor.visit_i32x4_lt_s(),
1524            0x3a => visitor.visit_i32x4_lt_u(),
1525            0x3b => visitor.visit_i32x4_gt_s(),
1526            0x3c => visitor.visit_i32x4_gt_u(),
1527            0x3d => visitor.visit_i32x4_le_s(),
1528            0x3e => visitor.visit_i32x4_le_u(),
1529            0x3f => visitor.visit_i32x4_ge_s(),
1530            0x40 => visitor.visit_i32x4_ge_u(),
1531            0x41 => visitor.visit_f32x4_eq(),
1532            0x42 => visitor.visit_f32x4_ne(),
1533            0x43 => visitor.visit_f32x4_lt(),
1534            0x44 => visitor.visit_f32x4_gt(),
1535            0x45 => visitor.visit_f32x4_le(),
1536            0x46 => visitor.visit_f32x4_ge(),
1537            0x47 => visitor.visit_f64x2_eq(),
1538            0x48 => visitor.visit_f64x2_ne(),
1539            0x49 => visitor.visit_f64x2_lt(),
1540            0x4a => visitor.visit_f64x2_gt(),
1541            0x4b => visitor.visit_f64x2_le(),
1542            0x4c => visitor.visit_f64x2_ge(),
1543            0x4d => visitor.visit_v128_not(),
1544            0x4e => visitor.visit_v128_and(),
1545            0x4f => visitor.visit_v128_andnot(),
1546            0x50 => visitor.visit_v128_or(),
1547            0x51 => visitor.visit_v128_xor(),
1548            0x52 => visitor.visit_v128_bitselect(),
1549            0x53 => visitor.visit_v128_any_true(),
1550
1551            0x54 => {
1552                let memarg = self.read_memarg(0)?;
1553                let lane = self.read_lane_index()?;
1554                visitor.visit_v128_load8_lane(memarg, lane)
1555            }
1556            0x55 => {
1557                let memarg = self.read_memarg(1)?;
1558                let lane = self.read_lane_index()?;
1559                visitor.visit_v128_load16_lane(memarg, lane)
1560            }
1561            0x56 => {
1562                let memarg = self.read_memarg(2)?;
1563                let lane = self.read_lane_index()?;
1564                visitor.visit_v128_load32_lane(memarg, lane)
1565            }
1566            0x57 => {
1567                let memarg = self.read_memarg(3)?;
1568                let lane = self.read_lane_index()?;
1569                visitor.visit_v128_load64_lane(memarg, lane)
1570            }
1571            0x58 => {
1572                let memarg = self.read_memarg(0)?;
1573                let lane = self.read_lane_index()?;
1574                visitor.visit_v128_store8_lane(memarg, lane)
1575            }
1576            0x59 => {
1577                let memarg = self.read_memarg(1)?;
1578                let lane = self.read_lane_index()?;
1579                visitor.visit_v128_store16_lane(memarg, lane)
1580            }
1581            0x5a => {
1582                let memarg = self.read_memarg(2)?;
1583                let lane = self.read_lane_index()?;
1584                visitor.visit_v128_store32_lane(memarg, lane)
1585            }
1586            0x5b => {
1587                let memarg = self.read_memarg(3)?;
1588                let lane = self.read_lane_index()?;
1589                visitor.visit_v128_store64_lane(memarg, lane)
1590            }
1591
1592            0x5c => visitor.visit_v128_load32_zero(self.read_memarg(2)?),
1593            0x5d => visitor.visit_v128_load64_zero(self.read_memarg(3)?),
1594            0x5e => visitor.visit_f32x4_demote_f64x2_zero(),
1595            0x5f => visitor.visit_f64x2_promote_low_f32x4(),
1596            0x60 => visitor.visit_i8x16_abs(),
1597            0x61 => visitor.visit_i8x16_neg(),
1598            0x62 => visitor.visit_i8x16_popcnt(),
1599            0x63 => visitor.visit_i8x16_all_true(),
1600            0x64 => visitor.visit_i8x16_bitmask(),
1601            0x65 => visitor.visit_i8x16_narrow_i16x8_s(),
1602            0x66 => visitor.visit_i8x16_narrow_i16x8_u(),
1603            0x67 => visitor.visit_f32x4_ceil(),
1604            0x68 => visitor.visit_f32x4_floor(),
1605            0x69 => visitor.visit_f32x4_trunc(),
1606            0x6a => visitor.visit_f32x4_nearest(),
1607            0x6b => visitor.visit_i8x16_shl(),
1608            0x6c => visitor.visit_i8x16_shr_s(),
1609            0x6d => visitor.visit_i8x16_shr_u(),
1610            0x6e => visitor.visit_i8x16_add(),
1611            0x6f => visitor.visit_i8x16_add_sat_s(),
1612            0x70 => visitor.visit_i8x16_add_sat_u(),
1613            0x71 => visitor.visit_i8x16_sub(),
1614            0x72 => visitor.visit_i8x16_sub_sat_s(),
1615            0x73 => visitor.visit_i8x16_sub_sat_u(),
1616            0x74 => visitor.visit_f64x2_ceil(),
1617            0x75 => visitor.visit_f64x2_floor(),
1618            0x76 => visitor.visit_i8x16_min_s(),
1619            0x77 => visitor.visit_i8x16_min_u(),
1620            0x78 => visitor.visit_i8x16_max_s(),
1621            0x79 => visitor.visit_i8x16_max_u(),
1622            0x7a => visitor.visit_f64x2_trunc(),
1623            0x7b => visitor.visit_i8x16_avgr_u(),
1624            0x7c => visitor.visit_i16x8_extadd_pairwise_i8x16_s(),
1625            0x7d => visitor.visit_i16x8_extadd_pairwise_i8x16_u(),
1626            0x7e => visitor.visit_i32x4_extadd_pairwise_i16x8_s(),
1627            0x7f => visitor.visit_i32x4_extadd_pairwise_i16x8_u(),
1628            0x80 => visitor.visit_i16x8_abs(),
1629            0x81 => visitor.visit_i16x8_neg(),
1630            0x82 => visitor.visit_i16x8_q15mulr_sat_s(),
1631            0x83 => visitor.visit_i16x8_all_true(),
1632            0x84 => visitor.visit_i16x8_bitmask(),
1633            0x85 => visitor.visit_i16x8_narrow_i32x4_s(),
1634            0x86 => visitor.visit_i16x8_narrow_i32x4_u(),
1635            0x87 => visitor.visit_i16x8_extend_low_i8x16_s(),
1636            0x88 => visitor.visit_i16x8_extend_high_i8x16_s(),
1637            0x89 => visitor.visit_i16x8_extend_low_i8x16_u(),
1638            0x8a => visitor.visit_i16x8_extend_high_i8x16_u(),
1639            0x8b => visitor.visit_i16x8_shl(),
1640            0x8c => visitor.visit_i16x8_shr_s(),
1641            0x8d => visitor.visit_i16x8_shr_u(),
1642            0x8e => visitor.visit_i16x8_add(),
1643            0x8f => visitor.visit_i16x8_add_sat_s(),
1644            0x90 => visitor.visit_i16x8_add_sat_u(),
1645            0x91 => visitor.visit_i16x8_sub(),
1646            0x92 => visitor.visit_i16x8_sub_sat_s(),
1647            0x93 => visitor.visit_i16x8_sub_sat_u(),
1648            0x94 => visitor.visit_f64x2_nearest(),
1649            0x95 => visitor.visit_i16x8_mul(),
1650            0x96 => visitor.visit_i16x8_min_s(),
1651            0x97 => visitor.visit_i16x8_min_u(),
1652            0x98 => visitor.visit_i16x8_max_s(),
1653            0x99 => visitor.visit_i16x8_max_u(),
1654            0x9b => visitor.visit_i16x8_avgr_u(),
1655            0x9c => visitor.visit_i16x8_extmul_low_i8x16_s(),
1656            0x9d => visitor.visit_i16x8_extmul_high_i8x16_s(),
1657            0x9e => visitor.visit_i16x8_extmul_low_i8x16_u(),
1658            0x9f => visitor.visit_i16x8_extmul_high_i8x16_u(),
1659            0xa0 => visitor.visit_i32x4_abs(),
1660            0xa1 => visitor.visit_i32x4_neg(),
1661            0xa3 => visitor.visit_i32x4_all_true(),
1662            0xa4 => visitor.visit_i32x4_bitmask(),
1663            0xa7 => visitor.visit_i32x4_extend_low_i16x8_s(),
1664            0xa8 => visitor.visit_i32x4_extend_high_i16x8_s(),
1665            0xa9 => visitor.visit_i32x4_extend_low_i16x8_u(),
1666            0xaa => visitor.visit_i32x4_extend_high_i16x8_u(),
1667            0xab => visitor.visit_i32x4_shl(),
1668            0xac => visitor.visit_i32x4_shr_s(),
1669            0xad => visitor.visit_i32x4_shr_u(),
1670            0xae => visitor.visit_i32x4_add(),
1671            0xb1 => visitor.visit_i32x4_sub(),
1672            0xb5 => visitor.visit_i32x4_mul(),
1673            0xb6 => visitor.visit_i32x4_min_s(),
1674            0xb7 => visitor.visit_i32x4_min_u(),
1675            0xb8 => visitor.visit_i32x4_max_s(),
1676            0xb9 => visitor.visit_i32x4_max_u(),
1677            0xba => visitor.visit_i32x4_dot_i16x8_s(),
1678            0xbc => visitor.visit_i32x4_extmul_low_i16x8_s(),
1679            0xbd => visitor.visit_i32x4_extmul_high_i16x8_s(),
1680            0xbe => visitor.visit_i32x4_extmul_low_i16x8_u(),
1681            0xbf => visitor.visit_i32x4_extmul_high_i16x8_u(),
1682            0xc0 => visitor.visit_i64x2_abs(),
1683            0xc1 => visitor.visit_i64x2_neg(),
1684            0xc3 => visitor.visit_i64x2_all_true(),
1685            0xc4 => visitor.visit_i64x2_bitmask(),
1686            0xc7 => visitor.visit_i64x2_extend_low_i32x4_s(),
1687            0xc8 => visitor.visit_i64x2_extend_high_i32x4_s(),
1688            0xc9 => visitor.visit_i64x2_extend_low_i32x4_u(),
1689            0xca => visitor.visit_i64x2_extend_high_i32x4_u(),
1690            0xcb => visitor.visit_i64x2_shl(),
1691            0xcc => visitor.visit_i64x2_shr_s(),
1692            0xcd => visitor.visit_i64x2_shr_u(),
1693            0xce => visitor.visit_i64x2_add(),
1694            0xd1 => visitor.visit_i64x2_sub(),
1695            0xd5 => visitor.visit_i64x2_mul(),
1696            0xd6 => visitor.visit_i64x2_eq(),
1697            0xd7 => visitor.visit_i64x2_ne(),
1698            0xd8 => visitor.visit_i64x2_lt_s(),
1699            0xd9 => visitor.visit_i64x2_gt_s(),
1700            0xda => visitor.visit_i64x2_le_s(),
1701            0xdb => visitor.visit_i64x2_ge_s(),
1702            0xdc => visitor.visit_i64x2_extmul_low_i32x4_s(),
1703            0xdd => visitor.visit_i64x2_extmul_high_i32x4_s(),
1704            0xde => visitor.visit_i64x2_extmul_low_i32x4_u(),
1705            0xdf => visitor.visit_i64x2_extmul_high_i32x4_u(),
1706            0xe0 => visitor.visit_f32x4_abs(),
1707            0xe1 => visitor.visit_f32x4_neg(),
1708            0xe3 => visitor.visit_f32x4_sqrt(),
1709            0xe4 => visitor.visit_f32x4_add(),
1710            0xe5 => visitor.visit_f32x4_sub(),
1711            0xe6 => visitor.visit_f32x4_mul(),
1712            0xe7 => visitor.visit_f32x4_div(),
1713            0xe8 => visitor.visit_f32x4_min(),
1714            0xe9 => visitor.visit_f32x4_max(),
1715            0xea => visitor.visit_f32x4_pmin(),
1716            0xeb => visitor.visit_f32x4_pmax(),
1717            0xec => visitor.visit_f64x2_abs(),
1718            0xed => visitor.visit_f64x2_neg(),
1719            0xef => visitor.visit_f64x2_sqrt(),
1720            0xf0 => visitor.visit_f64x2_add(),
1721            0xf1 => visitor.visit_f64x2_sub(),
1722            0xf2 => visitor.visit_f64x2_mul(),
1723            0xf3 => visitor.visit_f64x2_div(),
1724            0xf4 => visitor.visit_f64x2_min(),
1725            0xf5 => visitor.visit_f64x2_max(),
1726            0xf6 => visitor.visit_f64x2_pmin(),
1727            0xf7 => visitor.visit_f64x2_pmax(),
1728            0xf8 => visitor.visit_i32x4_trunc_sat_f32x4_s(),
1729            0xf9 => visitor.visit_i32x4_trunc_sat_f32x4_u(),
1730            0xfa => visitor.visit_f32x4_convert_i32x4_s(),
1731            0xfb => visitor.visit_f32x4_convert_i32x4_u(),
1732            0xfc => visitor.visit_i32x4_trunc_sat_f64x2_s_zero(),
1733            0xfd => visitor.visit_i32x4_trunc_sat_f64x2_u_zero(),
1734            0xfe => visitor.visit_f64x2_convert_low_i32x4_s(),
1735            0xff => visitor.visit_f64x2_convert_low_i32x4_u(),
1736            0x100 => visitor.visit_i8x16_relaxed_swizzle(),
1737            0x101 => visitor.visit_i32x4_relaxed_trunc_f32x4_s(),
1738            0x102 => visitor.visit_i32x4_relaxed_trunc_f32x4_u(),
1739            0x103 => visitor.visit_i32x4_relaxed_trunc_f64x2_s_zero(),
1740            0x104 => visitor.visit_i32x4_relaxed_trunc_f64x2_u_zero(),
1741            0x105 => visitor.visit_f32x4_relaxed_madd(),
1742            0x106 => visitor.visit_f32x4_relaxed_nmadd(),
1743            0x107 => visitor.visit_f64x2_relaxed_madd(),
1744            0x108 => visitor.visit_f64x2_relaxed_nmadd(),
1745            0x109 => visitor.visit_i8x16_relaxed_laneselect(),
1746            0x10a => visitor.visit_i16x8_relaxed_laneselect(),
1747            0x10b => visitor.visit_i32x4_relaxed_laneselect(),
1748            0x10c => visitor.visit_i64x2_relaxed_laneselect(),
1749            0x10d => visitor.visit_f32x4_relaxed_min(),
1750            0x10e => visitor.visit_f32x4_relaxed_max(),
1751            0x10f => visitor.visit_f64x2_relaxed_min(),
1752            0x110 => visitor.visit_f64x2_relaxed_max(),
1753            0x111 => visitor.visit_i16x8_relaxed_q15mulr_s(),
1754            0x112 => visitor.visit_i16x8_relaxed_dot_i8x16_i7x16_s(),
1755            0x113 => visitor.visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(),
1756
1757            _ => bail!(pos, "unknown 0xfd subopcode: 0x{code:x}"),
1758        })
1759    }
1760
1761    fn visit_0xfe_operator<T>(
1762        &mut self,
1763        pos: usize,
1764        visitor: &mut T,
1765    ) -> Result<<T as VisitOperator<'a>>::Output>
1766    where
1767        T: VisitOperator<'a>,
1768    {
1769        let code = self.read_var_u32()?;
1770        Ok(match code {
1771            0x00 => visitor.visit_memory_atomic_notify(self.read_memarg(2)?),
1772            0x01 => visitor.visit_memory_atomic_wait32(self.read_memarg(2)?),
1773            0x02 => visitor.visit_memory_atomic_wait64(self.read_memarg(3)?),
1774            0x03 => {
1775                if self.read_u8()? != 0 {
1776                    bail!(pos, "nonzero byte after `atomic.fence`");
1777                }
1778                visitor.visit_atomic_fence()
1779            }
1780            0x10 => visitor.visit_i32_atomic_load(self.read_memarg(2)?),
1781            0x11 => visitor.visit_i64_atomic_load(self.read_memarg(3)?),
1782            0x12 => visitor.visit_i32_atomic_load8_u(self.read_memarg(0)?),
1783            0x13 => visitor.visit_i32_atomic_load16_u(self.read_memarg(1)?),
1784            0x14 => visitor.visit_i64_atomic_load8_u(self.read_memarg(0)?),
1785            0x15 => visitor.visit_i64_atomic_load16_u(self.read_memarg(1)?),
1786            0x16 => visitor.visit_i64_atomic_load32_u(self.read_memarg(2)?),
1787            0x17 => visitor.visit_i32_atomic_store(self.read_memarg(2)?),
1788            0x18 => visitor.visit_i64_atomic_store(self.read_memarg(3)?),
1789            0x19 => visitor.visit_i32_atomic_store8(self.read_memarg(0)?),
1790            0x1a => visitor.visit_i32_atomic_store16(self.read_memarg(1)?),
1791            0x1b => visitor.visit_i64_atomic_store8(self.read_memarg(0)?),
1792            0x1c => visitor.visit_i64_atomic_store16(self.read_memarg(1)?),
1793            0x1d => visitor.visit_i64_atomic_store32(self.read_memarg(2)?),
1794            0x1e => visitor.visit_i32_atomic_rmw_add(self.read_memarg(2)?),
1795            0x1f => visitor.visit_i64_atomic_rmw_add(self.read_memarg(3)?),
1796            0x20 => visitor.visit_i32_atomic_rmw8_add_u(self.read_memarg(0)?),
1797            0x21 => visitor.visit_i32_atomic_rmw16_add_u(self.read_memarg(1)?),
1798            0x22 => visitor.visit_i64_atomic_rmw8_add_u(self.read_memarg(0)?),
1799            0x23 => visitor.visit_i64_atomic_rmw16_add_u(self.read_memarg(1)?),
1800            0x24 => visitor.visit_i64_atomic_rmw32_add_u(self.read_memarg(2)?),
1801            0x25 => visitor.visit_i32_atomic_rmw_sub(self.read_memarg(2)?),
1802            0x26 => visitor.visit_i64_atomic_rmw_sub(self.read_memarg(3)?),
1803            0x27 => visitor.visit_i32_atomic_rmw8_sub_u(self.read_memarg(0)?),
1804            0x28 => visitor.visit_i32_atomic_rmw16_sub_u(self.read_memarg(1)?),
1805            0x29 => visitor.visit_i64_atomic_rmw8_sub_u(self.read_memarg(0)?),
1806            0x2a => visitor.visit_i64_atomic_rmw16_sub_u(self.read_memarg(1)?),
1807            0x2b => visitor.visit_i64_atomic_rmw32_sub_u(self.read_memarg(2)?),
1808            0x2c => visitor.visit_i32_atomic_rmw_and(self.read_memarg(2)?),
1809            0x2d => visitor.visit_i64_atomic_rmw_and(self.read_memarg(3)?),
1810            0x2e => visitor.visit_i32_atomic_rmw8_and_u(self.read_memarg(0)?),
1811            0x2f => visitor.visit_i32_atomic_rmw16_and_u(self.read_memarg(1)?),
1812            0x30 => visitor.visit_i64_atomic_rmw8_and_u(self.read_memarg(0)?),
1813            0x31 => visitor.visit_i64_atomic_rmw16_and_u(self.read_memarg(1)?),
1814            0x32 => visitor.visit_i64_atomic_rmw32_and_u(self.read_memarg(2)?),
1815            0x33 => visitor.visit_i32_atomic_rmw_or(self.read_memarg(2)?),
1816            0x34 => visitor.visit_i64_atomic_rmw_or(self.read_memarg(3)?),
1817            0x35 => visitor.visit_i32_atomic_rmw8_or_u(self.read_memarg(0)?),
1818            0x36 => visitor.visit_i32_atomic_rmw16_or_u(self.read_memarg(1)?),
1819            0x37 => visitor.visit_i64_atomic_rmw8_or_u(self.read_memarg(0)?),
1820            0x38 => visitor.visit_i64_atomic_rmw16_or_u(self.read_memarg(1)?),
1821            0x39 => visitor.visit_i64_atomic_rmw32_or_u(self.read_memarg(2)?),
1822            0x3a => visitor.visit_i32_atomic_rmw_xor(self.read_memarg(2)?),
1823            0x3b => visitor.visit_i64_atomic_rmw_xor(self.read_memarg(3)?),
1824            0x3c => visitor.visit_i32_atomic_rmw8_xor_u(self.read_memarg(0)?),
1825            0x3d => visitor.visit_i32_atomic_rmw16_xor_u(self.read_memarg(1)?),
1826            0x3e => visitor.visit_i64_atomic_rmw8_xor_u(self.read_memarg(0)?),
1827            0x3f => visitor.visit_i64_atomic_rmw16_xor_u(self.read_memarg(1)?),
1828            0x40 => visitor.visit_i64_atomic_rmw32_xor_u(self.read_memarg(2)?),
1829            0x41 => visitor.visit_i32_atomic_rmw_xchg(self.read_memarg(2)?),
1830            0x42 => visitor.visit_i64_atomic_rmw_xchg(self.read_memarg(3)?),
1831            0x43 => visitor.visit_i32_atomic_rmw8_xchg_u(self.read_memarg(0)?),
1832            0x44 => visitor.visit_i32_atomic_rmw16_xchg_u(self.read_memarg(1)?),
1833            0x45 => visitor.visit_i64_atomic_rmw8_xchg_u(self.read_memarg(0)?),
1834            0x46 => visitor.visit_i64_atomic_rmw16_xchg_u(self.read_memarg(1)?),
1835            0x47 => visitor.visit_i64_atomic_rmw32_xchg_u(self.read_memarg(2)?),
1836            0x48 => visitor.visit_i32_atomic_rmw_cmpxchg(self.read_memarg(2)?),
1837            0x49 => visitor.visit_i64_atomic_rmw_cmpxchg(self.read_memarg(3)?),
1838            0x4a => visitor.visit_i32_atomic_rmw8_cmpxchg_u(self.read_memarg(0)?),
1839            0x4b => visitor.visit_i32_atomic_rmw16_cmpxchg_u(self.read_memarg(1)?),
1840            0x4c => visitor.visit_i64_atomic_rmw8_cmpxchg_u(self.read_memarg(0)?),
1841            0x4d => visitor.visit_i64_atomic_rmw16_cmpxchg_u(self.read_memarg(1)?),
1842            0x4e => visitor.visit_i64_atomic_rmw32_cmpxchg_u(self.read_memarg(2)?),
1843
1844            // Decode shared-everything-threads proposal.
1845            0x4f => visitor.visit_global_atomic_get(self.read_ordering()?, self.read_var_u32()?),
1846            0x50 => visitor.visit_global_atomic_set(self.read_ordering()?, self.read_var_u32()?),
1847            0x51 => {
1848                visitor.visit_global_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?)
1849            }
1850            0x52 => {
1851                visitor.visit_global_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?)
1852            }
1853            0x53 => {
1854                visitor.visit_global_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?)
1855            }
1856            0x54 => visitor.visit_global_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?),
1857            0x55 => {
1858                visitor.visit_global_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?)
1859            }
1860            0x56 => {
1861                visitor.visit_global_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)
1862            }
1863            0x57 => {
1864                visitor.visit_global_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)
1865            }
1866            0x58 => visitor.visit_table_atomic_get(self.read_ordering()?, self.read_var_u32()?),
1867            0x59 => visitor.visit_table_atomic_set(self.read_ordering()?, self.read_var_u32()?),
1868            0x5a => {
1869                visitor.visit_table_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)
1870            }
1871            0x5b => {
1872                visitor.visit_table_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)
1873            }
1874            0x5c => visitor.visit_struct_atomic_get(
1875                self.read_ordering()?,
1876                self.read_var_u32()?,
1877                self.read_var_u32()?,
1878            ),
1879            0x5d => visitor.visit_struct_atomic_get_s(
1880                self.read_ordering()?,
1881                self.read_var_u32()?,
1882                self.read_var_u32()?,
1883            ),
1884            0x5e => visitor.visit_struct_atomic_get_u(
1885                self.read_ordering()?,
1886                self.read_var_u32()?,
1887                self.read_var_u32()?,
1888            ),
1889            0x5f => visitor.visit_struct_atomic_set(
1890                self.read_ordering()?,
1891                self.read_var_u32()?,
1892                self.read_var_u32()?,
1893            ),
1894            0x60 => visitor.visit_struct_atomic_rmw_add(
1895                self.read_ordering()?,
1896                self.read_var_u32()?,
1897                self.read_var_u32()?,
1898            ),
1899            0x61 => visitor.visit_struct_atomic_rmw_sub(
1900                self.read_ordering()?,
1901                self.read_var_u32()?,
1902                self.read_var_u32()?,
1903            ),
1904            0x62 => visitor.visit_struct_atomic_rmw_and(
1905                self.read_ordering()?,
1906                self.read_var_u32()?,
1907                self.read_var_u32()?,
1908            ),
1909            0x63 => visitor.visit_struct_atomic_rmw_or(
1910                self.read_ordering()?,
1911                self.read_var_u32()?,
1912                self.read_var_u32()?,
1913            ),
1914            0x64 => visitor.visit_struct_atomic_rmw_xor(
1915                self.read_ordering()?,
1916                self.read_var_u32()?,
1917                self.read_var_u32()?,
1918            ),
1919            0x65 => visitor.visit_struct_atomic_rmw_xchg(
1920                self.read_ordering()?,
1921                self.read_var_u32()?,
1922                self.read_var_u32()?,
1923            ),
1924            0x66 => visitor.visit_struct_atomic_rmw_cmpxchg(
1925                self.read_ordering()?,
1926                self.read_var_u32()?,
1927                self.read_var_u32()?,
1928            ),
1929            0x67 => visitor.visit_array_atomic_get(self.read_ordering()?, self.read_var_u32()?),
1930            0x68 => visitor.visit_array_atomic_get_s(self.read_ordering()?, self.read_var_u32()?),
1931            0x69 => visitor.visit_array_atomic_get_u(self.read_ordering()?, self.read_var_u32()?),
1932            0x6a => visitor.visit_array_atomic_set(self.read_ordering()?, self.read_var_u32()?),
1933            0x6b => visitor.visit_array_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?),
1934            0x6c => visitor.visit_array_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?),
1935            0x6d => visitor.visit_array_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?),
1936            0x6e => visitor.visit_array_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?),
1937            0x6f => visitor.visit_array_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?),
1938            0x70 => {
1939                visitor.visit_array_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)
1940            }
1941            0x71 => {
1942                visitor.visit_array_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)
1943            }
1944            0x72 => visitor.visit_ref_i31_shared(),
1945
1946            _ => bail!(pos, "unknown 0xfe subopcode: 0x{code:x}"),
1947        })
1948    }
1949
1950    fn read_memarg(&mut self, max_align: u8) -> Result<MemArg> {
1951        let flags_pos = self.original_position();
1952        let mut flags = self.read_var_u32()?;
1953
1954        let memory = if self.multi_memory() && flags & (1 << 6) != 0 {
1955            flags ^= 1 << 6;
1956            self.read_var_u32()?
1957        } else {
1958            0
1959        };
1960        let max_flag_bits = if self.multi_memory() { 6 } else { 5 };
1961        if flags >= (1 << max_flag_bits) {
1962            return Err(BinaryReaderError::new(
1963                "malformed memop alignment: alignment too large",
1964                flags_pos,
1965            ));
1966        }
1967        let align = flags as u8;
1968        let offset = if self.memory64() {
1969            self.read_var_u64()?
1970        } else {
1971            u64::from(self.read_var_u32()?)
1972        };
1973        Ok(MemArg {
1974            align,
1975            max_align,
1976            offset,
1977            memory,
1978        })
1979    }
1980
1981    fn read_ordering(&mut self) -> Result<Ordering> {
1982        let byte = self.read_var_u32()?;
1983        match byte {
1984            0 => Ok(Ordering::SeqCst),
1985            1 => Ok(Ordering::AcqRel),
1986            x => Err(BinaryReaderError::new(
1987                &format!("invalid atomic consistency ordering {x}"),
1988                self.original_position() - 1,
1989            )),
1990        }
1991    }
1992
1993    fn read_br_table(&mut self) -> Result<BrTable<'a>> {
1994        let cnt = self.read_size(MAX_WASM_BR_TABLE_SIZE, "br_table")?;
1995        let reader = self.skip(|reader| {
1996            for _ in 0..cnt {
1997                reader.read_var_u32()?;
1998            }
1999            Ok(())
2000        })?;
2001        let default = self.read_var_u32()?;
2002        Ok(BrTable {
2003            reader,
2004            cnt: cnt as u32,
2005            default,
2006        })
2007    }
2008
2009    #[cfg(feature = "simd")]
2010    fn read_lane_index(&mut self) -> Result<u8> {
2011        self.read_u8()
2012    }
2013
2014    #[cfg(feature = "simd")]
2015    fn read_v128(&mut self) -> Result<V128> {
2016        let mut bytes = [0; 16];
2017        bytes.clone_from_slice(self.read_bytes(16)?);
2018        Ok(V128(bytes))
2019    }
2020
2021    fn read_memory_index_or_zero_if_not_multi_memory(&mut self) -> Result<u32> {
2022        if self.multi_memory() {
2023            self.read_var_u32()
2024        } else {
2025            // Before bulk memory this byte was required to be a single zero
2026            // byte, not a LEB-encoded zero, so require a precise zero byte.
2027            match self.read_u8()? {
2028                0 => Ok(0),
2029                _ => bail!(self.original_position() - 1, "zero byte expected"),
2030            }
2031        }
2032    }
2033
2034    fn read_call_indirect_table_immediate(&mut self) -> Result<u32> {
2035        // If the `call_indirect_overlong` feature is enabled, then read this
2036        // immediate as a LEB. This feature is enabled as part of the
2037        // `reference_types` feature or the `lime1` feature.
2038        if self.call_indirect_overlong() {
2039            return self.read_var_u32();
2040        }
2041
2042        // Before reference types this byte was required to be a single zero
2043        // byte, not a LEB-encoded zero, so require a precise zero byte.
2044        match self.read_u8()? {
2045            0 => Ok(0),
2046            _ => bail!(self.original_position() - 1, "zero byte expected"),
2047        }
2048    }
2049}