wasm/validation/
data.rs

1use alloc::vec::Vec;
2
3use crate::{
4    core::{
5        indices::MemIdx,
6        reader::{
7            section_header::{SectionHeader, SectionTy},
8            types::{
9                data::{DataMode, DataModeActive, DataSegment},
10                global::GlobalType,
11            },
12            WasmReader,
13        },
14    },
15    read_constant_expression::read_constant_expression,
16    validation_stack::ValidationStack,
17    Result,
18};
19
20/// Validate the data section.
21pub(super) fn validate_data_section(
22    wasm: &mut WasmReader,
23    section_header: SectionHeader,
24    imported_global_types: &[GlobalType],
25    no_of_total_memories: usize,
26    num_funcs: usize,
27) -> Result<Vec<DataSegment>> {
28    assert_eq!(section_header.ty, SectionTy::Data);
29
30    wasm.read_vec(|wasm| {
31        use crate::{NumType, ValType};
32        let mode = wasm.read_var_u32()?;
33        let data_sec: DataSegment = match mode {
34            0 => {
35                // active { memory 0, offset e }
36                trace!("Data section: active {{ memory 0, offset e }}");
37                let mut valid_stack = ValidationStack::new();
38                let (offset, _) = {
39                    read_constant_expression(
40                        wasm,
41                        &mut valid_stack,
42                        imported_global_types,
43                        num_funcs,
44                    )?
45                };
46
47                valid_stack.assert_val_types(&[ValType::NumType(NumType::I32)], true)?;
48
49                let byte_vec = wasm.read_vec(|el| el.read_u8())?;
50
51                // WARN: we currently don't take into consideration how we act when we are dealing with globals here
52                DataSegment {
53                    mode: DataMode::Active(DataModeActive {
54                        memory_idx: 0,
55                        offset,
56                    }),
57                    init: byte_vec,
58                }
59            }
60            1 => {
61                // passive
62                // A passive data segment's contents can be copied into a memory using the `memory.init` instruction
63                trace!("Data section: passive");
64                DataSegment {
65                    mode: DataMode::Passive,
66                    init: wasm.read_vec(|el| el.read_u8())?,
67                }
68            }
69            2 => {
70                trace!("Data section: active {{ memory x, offset e }}");
71                let mem_idx = wasm.read_var_u32()? as MemIdx;
72                if mem_idx >= no_of_total_memories {
73                    return Err(crate::Error::UnknownMemory);
74                }
75                assert!(
76                    mem_idx == 0,
77                    "Memory index is not 0 - it's {}! Multiple memories are NOT supported",
78                    mem_idx
79                );
80
81                let mut valid_stack = ValidationStack::new();
82                let (offset, _) = {
83                    read_constant_expression(
84                        wasm,
85                        &mut valid_stack,
86                        imported_global_types,
87                        num_funcs,
88                    )?
89                };
90
91                valid_stack.assert_val_types(&[ValType::NumType(NumType::I32)], true)?;
92
93                let byte_vec = wasm.read_vec(|el| el.read_u8())?;
94
95                DataSegment {
96                    mode: DataMode::Active(DataModeActive {
97                        memory_idx: 0,
98                        offset,
99                    }),
100                    init: byte_vec,
101                }
102                // mode active { memory x, offset e }
103                // this hasn't been yet implemented in wasm
104                // as per docs:
105
106                // https://webassembly.github.io/spec/core/binary/modules.html#data-section
107                // The initial integer can be interpreted as a bitfield. Bit 0 indicates a passive segment, bit 1 indicates the presence of an explicit memory index for an active segment.
108                // In the current version of WebAssembly, at most one memory may be defined or imported in a single module, so all valid active data segments have a memory value of 0
109            }
110            _ => unreachable!(),
111        };
112
113        trace!("{:?}", data_sec.init);
114        Ok(data_sec)
115    })
116}