1use alloc::{borrow::ToOwned, string::String, vec::Vec};
10
11use crate::binary::leb128::{self, Cursor};
12use crate::binary::section::RawSection;
13use crate::binary::typeparser::{
14 parse_ref_type as parse_binary_ref_type, parse_val_type as parse_binary_val_type,
15};
16use crate::error::{ByteOffset, DecodeContext, DecodeError, DecodeErrorKind};
17use crate::types::{
18 GlobalType, Import, ImportDesc, Limits, MemType, Mutability, RefType, TableType, TypeIdx,
19 ValType,
20};
21
22pub fn parse_import_section(section: &RawSection<'_>) -> Result<Vec<Import>, DecodeError> {
23 let mut cursor = Cursor::new(section.data);
24 let count = decode_u32_in_section(&mut cursor, section.offset, DecodeContext::ImportSection)?;
25
26 let mut imports = Vec::with_capacity(cursor.capacity_hint(count));
27 for _ in 0..count {
28 let module = parse_name(&mut cursor, section.offset)?;
29 let name = parse_name(&mut cursor, section.offset)?;
30 let desc = parse_import_desc(&mut cursor, section.offset)?;
31 imports.push(Import { module, name, desc });
32 }
33
34 if !cursor.is_empty() {
35 return Err(DecodeError {
36 offset: ByteOffset(section.offset + cursor.position()),
37 context: DecodeContext::ImportSection,
38 kind: DecodeErrorKind::SectionSizeMismatch {
39 expected: section.data.len() as u32,
40 consumed: cursor.position() as u32,
41 },
42 });
43 }
44
45 Ok(imports)
46}
47
48fn parse_import_desc(
49 cursor: &mut Cursor<'_>,
50 base_offset: usize,
51) -> Result<ImportDesc, DecodeError> {
52 let offset = cursor.position();
53 let byte = cursor.read_byte().map_err(|_| DecodeError {
54 offset: ByteOffset(base_offset + offset),
55 context: DecodeContext::ImportSection,
56 kind: DecodeErrorKind::UnexpectedEof,
57 })?;
58
59 match byte {
60 0x00 => {
61 let type_idx =
62 decode_u32_in_section(cursor, base_offset, DecodeContext::ImportSection)?;
63 Ok(ImportDesc::Func(TypeIdx(type_idx)))
64 }
65 0x01 => Ok(ImportDesc::Table(parse_table_type(cursor, base_offset)?)),
66 0x02 => Ok(ImportDesc::Mem(MemType {
67 limits: parse_limits(cursor, base_offset)?,
68 })),
69 0x03 => Ok(ImportDesc::Global(parse_global_type(cursor, base_offset)?)),
70 _ => Err(DecodeError {
71 offset: ByteOffset(base_offset + offset),
72 context: DecodeContext::ImportSection,
73 kind: DecodeErrorKind::UnknownImportDesc { byte },
74 }),
75 }
76}
77
78fn parse_table_type(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<TableType, DecodeError> {
79 let elem = parse_ref_type(cursor, base_offset)?;
80 let limits = parse_limits(cursor, base_offset)?;
81 Ok(TableType {
82 elem,
83 limits,
84 init: None,
85 })
86}
87
88fn parse_global_type(
89 cursor: &mut Cursor<'_>,
90 base_offset: usize,
91) -> Result<GlobalType, DecodeError> {
92 let val_type = parse_val_type(cursor, base_offset)?;
93 let mutability = parse_mutability(cursor, base_offset)?;
94 Ok(GlobalType {
95 val_type,
96 mutability,
97 })
98}
99
100fn parse_limits(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<Limits, DecodeError> {
101 let tag_offset = cursor.position();
102 let tag = cursor.read_byte().map_err(|_| DecodeError {
103 offset: ByteOffset(base_offset + tag_offset),
104 context: DecodeContext::ImportSection,
105 kind: DecodeErrorKind::UnexpectedEof,
106 })?;
107
108 match tag {
109 0x00 => {
110 let min = decode_u32_in_section(cursor, base_offset, DecodeContext::ImportSection)?;
111 Ok(Limits { min, max: None })
112 }
113 0x01 => {
114 let min = decode_u32_in_section(cursor, base_offset, DecodeContext::ImportSection)?;
115 let max = decode_u32_in_section(cursor, base_offset, DecodeContext::ImportSection)?;
116 Ok(Limits {
117 min,
118 max: Some(max),
119 })
120 }
121 _ => Err(DecodeError {
122 offset: ByteOffset(base_offset + tag_offset),
123 context: DecodeContext::ImportSection,
124 kind: DecodeErrorKind::UnexpectedByte {
125 expected: 0x00,
126 found: tag,
127 },
128 }),
129 }
130}
131
132fn parse_name(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<String, DecodeError> {
133 let length = decode_u32_in_section(cursor, base_offset, DecodeContext::ImportSection)? as usize;
134 let offset = cursor.position();
135 let bytes = cursor.read_bytes(length).map_err(|_| DecodeError {
136 offset: ByteOffset(base_offset + offset),
137 context: DecodeContext::ImportSection,
138 kind: DecodeErrorKind::UnexpectedEof,
139 })?;
140
141 core::str::from_utf8(bytes)
142 .map(str::to_owned)
143 .map_err(|_| DecodeError {
144 offset: ByteOffset(base_offset + offset),
145 context: DecodeContext::ImportSection,
146 kind: DecodeErrorKind::InvalidUtf8,
147 })
148}
149
150fn parse_val_type(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<ValType, DecodeError> {
151 parse_binary_val_type(cursor, base_offset, DecodeContext::ImportSection)
152}
153
154fn parse_ref_type(cursor: &mut Cursor<'_>, base_offset: usize) -> Result<RefType, DecodeError> {
155 parse_binary_ref_type(cursor, base_offset, DecodeContext::ImportSection)
156}
157
158fn parse_mutability(
159 cursor: &mut Cursor<'_>,
160 base_offset: usize,
161) -> Result<Mutability, DecodeError> {
162 let offset = cursor.position();
163 let byte = cursor.read_byte().map_err(|_| DecodeError {
164 offset: ByteOffset(base_offset + offset),
165 context: DecodeContext::ImportSection,
166 kind: DecodeErrorKind::UnexpectedEof,
167 })?;
168
169 match byte {
170 0x00 => Ok(Mutability::Const),
171 0x01 => Ok(Mutability::Var),
172 _ => Err(DecodeError {
173 offset: ByteOffset(base_offset + offset),
174 context: DecodeContext::ImportSection,
175 kind: DecodeErrorKind::InvalidMutability { byte },
176 }),
177 }
178}
179
180fn decode_u32_in_section(
181 cursor: &mut Cursor<'_>,
182 base_offset: usize,
183 context: DecodeContext,
184) -> Result<u32, DecodeError> {
185 leb128::decode_u32(cursor).map_err(|mut e| {
186 e.context = context;
187 e.offset = ByteOffset(base_offset + e.offset.0);
188 e
189 })
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use crate::binary::section::SectionId;
196 use crate::types::NumType;
197
198 fn raw_import_section(data: &[u8]) -> RawSection<'_> {
199 RawSection {
200 id: SectionId::Import,
201 offset: 20,
202 data,
203 }
204 }
205
206 #[test]
207 fn parse_empty_import_section() {
208 let section = raw_import_section(&[0x00]);
209 let imports = parse_import_section(§ion).unwrap();
210 assert!(imports.is_empty());
211 }
212
213 #[test]
214 fn parse_function_and_memory_imports() {
215 let section = raw_import_section(&[
216 0x02, 0x03, b'e', b'n', b'v', 0x05, b'p', b'r', b'i', b'n', b't', 0x00, 0x01, 0x03,
217 b'e', b'n', b'v', 0x03, b'm', b'e', b'm', 0x02, 0x01, 0x01, 0x02,
218 ]);
219
220 let imports = parse_import_section(§ion).unwrap();
221 assert_eq!(imports.len(), 2);
222 assert_eq!(imports[0].module, "env");
223 assert_eq!(imports[0].name, "print");
224 assert_eq!(imports[0].desc, ImportDesc::Func(TypeIdx(1)));
225 assert_eq!(imports[1].name, "mem");
226 assert_eq!(
227 imports[1].desc,
228 ImportDesc::Mem(MemType {
229 limits: Limits {
230 min: 1,
231 max: Some(2),
232 },
233 })
234 );
235 }
236
237 #[test]
238 fn parse_global_import() {
239 let section =
240 raw_import_section(&[0x01, 0x03, b'e', b'n', b'v', 0x01, b'g', 0x03, 0x7F, 0x01]);
241 let imports = parse_import_section(§ion).unwrap();
242 assert_eq!(
243 imports[0].desc,
244 ImportDesc::Global(GlobalType {
245 val_type: ValType::Num(NumType::I32),
246 mutability: Mutability::Var,
247 })
248 );
249 }
250
251 #[test]
252 fn reject_unknown_import_descriptor() {
253 let section = raw_import_section(&[0x01, 0x01, b'm', 0x01, b'n', 0x09]);
254 let err = parse_import_section(§ion).unwrap_err();
255 assert_eq!(err.kind, DecodeErrorKind::UnknownImportDesc { byte: 0x09 });
256 }
257
258 #[test]
259 fn reject_invalid_utf8_name() {
260 let section = raw_import_section(&[0x01, 0x01, 0xFF, 0x01, b'n', 0x00, 0x00]);
261 let err = parse_import_section(§ion).unwrap_err();
262 assert_eq!(err.kind, DecodeErrorKind::InvalidUtf8);
263 }
264
265 #[test]
266 fn reject_invalid_mutability() {
267 let section = raw_import_section(&[0x01, 0x01, b'm', 0x01, b'g', 0x03, 0x7F, 0x02]);
268 let err = parse_import_section(§ion).unwrap_err();
269 assert_eq!(err.kind, DecodeErrorKind::InvalidMutability { byte: 0x02 });
270 }
271}