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    ValidationError,
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>, ValidationError> {
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
38                if no_of_total_memories == 0 {
39                    return Err(ValidationError::UnknownMemory);
40                }
41
42                let mut valid_stack = ValidationStack::new();
43                let (offset, _) = {
44                    read_constant_expression(
45                        wasm,
46                        &mut valid_stack,
47                        imported_global_types,
48                        num_funcs,
49                    )?
50                };
51
52                valid_stack.assert_val_types(&[ValType::NumType(NumType::I32)], true)?;
53
54                let byte_vec = wasm.read_vec(|el| el.read_u8())?;
55
56                // WARN: we currently don't take into consideration how we act when we are dealing with globals here
57                DataSegment {
58                    mode: DataMode::Active(DataModeActive {
59                        memory_idx: 0,
60                        offset,
61                    }),
62                    init: byte_vec,
63                }
64            }
65            1 => {
66                // passive
67                // A passive data segment's contents can be copied into a memory using the `memory.init` instruction
68                trace!("Data section: passive");
69                DataSegment {
70                    mode: DataMode::Passive,
71                    init: wasm.read_vec(|el| el.read_u8())?,
72                }
73            }
74            2 => {
75                trace!("Data section: active {{ memory x, offset e }}");
76                let mem_idx = wasm.read_var_u32()? as MemIdx;
77                if mem_idx >= no_of_total_memories {
78                    return Err(crate::ValidationError::UnknownMemory);
79                }
80                assert!(
81                    mem_idx == 0,
82                    "Memory index is not 0 - it's {mem_idx}! Multiple memories are NOT supported"
83                );
84
85                let mut valid_stack = ValidationStack::new();
86                let (offset, _) = {
87                    read_constant_expression(
88                        wasm,
89                        &mut valid_stack,
90                        imported_global_types,
91                        num_funcs,
92                    )?
93                };
94
95                valid_stack.assert_val_types(&[ValType::NumType(NumType::I32)], true)?;
96
97                let byte_vec = wasm.read_vec(|el| el.read_u8())?;
98
99                DataSegment {
100                    mode: DataMode::Active(DataModeActive {
101                        memory_idx: 0,
102                        offset,
103                    }),
104                    init: byte_vec,
105                }
106                // mode active { memory x, offset e }
107                // this hasn't been yet implemented in wasm
108                // as per docs:
109
110                // https://webassembly.github.io/spec/core/binary/modules.html#data-section
111                // 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.
112                // 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
113            }
114            _ => unreachable!(),
115        };
116
117        trace!("{:?}", data_sec.init);
118        Ok(data_sec)
119    })
120}