wasmparser/readers/core/
data.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::{BinaryReader, BinaryReaderError, ConstExpr, FromReader, Result, SectionLimited};
17use core::ops::Range;
18
19/// Represents a data segment in a core WebAssembly module.
20#[derive(Debug, Clone)]
21pub struct Data<'a> {
22    /// The kind of data segment.
23    pub kind: DataKind<'a>,
24    /// The data of the data segment.
25    pub data: &'a [u8],
26    /// The range of the data segment.
27    pub range: Range<usize>,
28}
29
30/// The kind of data segment.
31#[derive(Debug, Clone)]
32pub enum DataKind<'a> {
33    /// The data segment is passive.
34    Passive,
35    /// The data segment is active.
36    Active {
37        /// The memory index for the data segment.
38        memory_index: u32,
39        /// The initialization expression for the data segment.
40        offset_expr: ConstExpr<'a>,
41    },
42}
43
44/// A reader for the data section of a WebAssembly module.
45pub type DataSectionReader<'a> = SectionLimited<'a, Data<'a>>;
46
47impl<'a> FromReader<'a> for Data<'a> {
48    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
49        let segment_start = reader.original_position();
50
51        // The current handling of the flags is largely specified in the `bulk-memory` proposal,
52        // which at the time this comment is written has been merged to the main specification
53        // draft.
54        //
55        // Notably, this proposal allows multiple different encodings of the memory index 0. `00`
56        // and `02 00` are both valid ways to specify the 0-th memory. However it also makes
57        // another encoding of the 0-th memory `80 00` no longer valid.
58        //
59        // We, however maintain this by parsing `flags` as a LEB128 integer. In that case, `80 00`
60        // encoding is parsed out as `0` and is therefore assigned a `memidx` 0, even though the
61        // current specification draft does not allow for this.
62        //
63        // See also https://github.com/WebAssembly/spec/issues/1439
64        let flags = reader.read_var_u32()?;
65        let kind = match flags {
66            1 => DataKind::Passive,
67            0 | 2 => {
68                let memory_index = if flags == 0 {
69                    0
70                } else {
71                    reader.read_var_u32()?
72                };
73                let offset_expr = reader.read()?;
74                DataKind::Active {
75                    memory_index,
76                    offset_expr,
77                }
78            }
79            _ => {
80                return Err(BinaryReaderError::new(
81                    "invalid flags byte in data segment",
82                    segment_start,
83                ));
84            }
85        };
86
87        let data = reader.read_reader()?;
88        Ok(Data {
89            kind,
90            data: data.remaining_buffer(),
91            range: segment_start..data.range().end,
92        })
93    }
94}