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 {mem_idx}! Multiple memories are NOT supported"
78                );
79
80                let mut valid_stack = ValidationStack::new();
81                let (offset, _) = {
82                    read_constant_expression(
83                        wasm,
84                        &mut valid_stack,
85                        imported_global_types,
86                        num_funcs,
87                    )?
88                };
89
90                valid_stack.assert_val_types(&[ValType::NumType(NumType::I32)], true)?;
91
92                let byte_vec = wasm.read_vec(|el| el.read_u8())?;
93
94                DataSegment {
95                    mode: DataMode::Active(DataModeActive {
96                        memory_idx: 0,
97                        offset,
98                    }),
99                    init: byte_vec,
100                }
101                // mode active { memory x, offset e }
102                // this hasn't been yet implemented in wasm
103                // as per docs:
104
105                // https://webassembly.github.io/spec/core/binary/modules.html#data-section
106                // 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.
107                // 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
108            }
109            _ => unreachable!(),
110        };
111
112        trace!("{:?}", data_sec.init);
113        Ok(data_sec)
114    })
115}