Skip to content

Commit 970a7ac

Browse files
refactor: improve reading of custom sections
Signed-off-by: Florian Hartung <florian.hartung@dlr.de>
1 parent 100fd8f commit 970a7ac

File tree

2 files changed

+85
-70
lines changed

2 files changed

+85
-70
lines changed

src/validation/custom_section.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use crate::{
2+
core::reader::{
3+
section_header::{SectionHeader, SectionTy},
4+
WasmReader,
5+
},
6+
ValidationError,
7+
};
8+
9+
#[derive(Debug, Clone)]
10+
pub struct CustomSection<'wasm> {
11+
pub name: &'wasm str,
12+
pub contents: &'wasm [u8],
13+
}
14+
15+
impl<'wasm> CustomSection<'wasm> {
16+
/// Reads and validates a custom section.
17+
pub(crate) fn read_and_validate(
18+
wasm: &mut WasmReader<'wasm>,
19+
header: SectionHeader,
20+
) -> Result<CustomSection<'wasm>, ValidationError> {
21+
assert_eq!(header.ty, SectionTy::Custom);
22+
23+
// customsec ::= section_0(custom)
24+
// custom ::= name byte*
25+
// name ::= b*:vec(byte) => name (if utf8(name) = b*)
26+
// vec(B) ::= n:u32 (x:B)^n => x^n
27+
let name = wasm.read_name()?;
28+
29+
let section_start = wasm.pc;
30+
let section_end = header
31+
.contents
32+
.from()
33+
.checked_add(header.contents.len())
34+
.ok_or(ValidationError::InvalidCustomSectionLength)?;
35+
36+
let contents = wasm
37+
.full_wasm_binary
38+
.get(section_start..section_end)
39+
.ok_or(ValidationError::InvalidCustomSectionLength)?;
40+
41+
let section_len = section_end
42+
.checked_sub(section_start)
43+
.expect("section start <= section end always");
44+
45+
wasm.skip(section_len)?;
46+
47+
Ok(CustomSection { name, contents })
48+
}
49+
}

src/validation/mod.rs

Lines changed: 36 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ use crate::core::reader::types::{ExternType, FuncType, MemType, ResultType, Tabl
1818
use crate::core::reader::WasmReader;
1919
use crate::core::sidetable::Sidetable;
2020
use crate::core::utils::ToUsizeExt;
21+
use crate::custom_section::CustomSection;
2122
use crate::ValidationError;
2223

2324
pub(crate) mod code;
25+
pub(crate) mod custom_section;
2426
pub(crate) mod data;
2527
pub(crate) mod globals;
2628
pub(crate) mod read_constant_expression;
@@ -49,7 +51,7 @@ pub struct ValidationInfo<'bytecode> {
4951
pub(crate) sidetable: Sidetable,
5052
/// The start function which is automatically executed during instantiation
5153
pub(crate) start: Option<FuncIdx>,
52-
pub(crate) custom_sections: Vec<(&'bytecode str, &'bytecode [u8])>,
54+
pub(crate) custom_sections: Vec<CustomSection<'bytecode>>,
5355
// pub(crate) exports_length: Exported,
5456
}
5557

@@ -95,27 +97,21 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
9597
read_next_header(&mut wasm, &mut header)?;
9698

9799
let mut custom_sections = Vec::new();
98-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
99-
custom_sections.push(custom_section);
100-
}
100+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
101101

102102
let types = handle_section(&mut wasm, &mut header, SectionTy::Type, |wasm, _| {
103103
wasm.read_vec(FuncType::read).map(|types| IdxVec::new(types).expect("that index space creation never fails because the length of the types vector is encoded as a 32-bit integer in the bytecode"))
104104
})?
105105
.unwrap_or_default();
106106

107-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
108-
custom_sections.push(custom_section);
109-
}
107+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
110108

111109
let imports = handle_section(&mut wasm, &mut header, SectionTy::Import, |wasm, _| {
112110
wasm.read_vec(|wasm| Import::read_and_validate(wasm, &types))
113111
})?
114112
.unwrap_or_default();
115113

116-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
117-
custom_sections.push(custom_section);
118-
}
114+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
119115

120116
// The `Function` section only covers module-level (or "local") functions.
121117
// Imported functions have their types known in the `import` section. Both
@@ -137,9 +133,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
137133
let functions = ExtendedIdxVec::new(imported_functions.collect(), local_functions)
138134
.map_err(|IdxVecOverflowError| ValidationError::TooManyFunctions)?;
139135

140-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
141-
custom_sections.push(custom_section);
142-
}
136+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
143137

144138
let imported_tables = imports.iter().filter_map(|m| match m.desc {
145139
ImportDesc::Table(table) => Some(table),
@@ -153,9 +147,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
153147
let tables = ExtendedIdxVec::new(imported_tables.collect(), local_tables)
154148
.map_err(|IdxVecOverflowError| ValidationError::TooManyTables)?;
155149

156-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
157-
custom_sections.push(custom_section);
158-
}
150+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
159151

160152
let imported_memories = imports.iter().filter_map(|m| match m.desc {
161153
ImportDesc::Mem(mem) => Some(mem),
@@ -174,9 +166,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
174166
return Err(ValidationError::UnsupportedMultipleMemoriesProposal);
175167
}
176168

177-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
178-
custom_sections.push(custom_section);
179-
}
169+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
180170

181171
let imported_global_types: Vec<GlobalType> = imports
182172
.iter()
@@ -205,9 +195,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
205195
let globals = ExtendedIdxVec::new(imported_globals.collect(), local_globals)
206196
.map_err(|IdxVecOverflowError| ValidationError::TooManyGlobals)?;
207197

208-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
209-
custom_sections.push(custom_section);
210-
}
198+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
211199

212200
let exports = handle_section(&mut wasm, &mut header, SectionTy::Export, |wasm, _| {
213201
wasm.read_vec(|wasm| {
@@ -228,9 +216,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
228216
},
229217
));
230218

231-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
232-
custom_sections.push(custom_section);
233-
}
219+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
234220

235221
let start = handle_section(&mut wasm, &mut header, SectionTy::Start, |wasm, _| {
236222
let func_idx = FuncIdx::read_and_validate(wasm, functions.inner())?;
@@ -261,9 +247,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
261247
}
262248
})?;
263249

264-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
265-
custom_sections.push(custom_section);
266-
}
250+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
267251

268252
let elements = handle_section(&mut wasm, &mut header, SectionTy::Element, |wasm, _| {
269253
ElemType::read_and_validate(
@@ -277,9 +261,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
277261
})?
278262
.unwrap_or_default();
279263

280-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
281-
custom_sections.push(custom_section);
282-
}
264+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
283265

284266
// https://webassembly.github.io/spec/core/binary/modules.html#data-count-section
285267
// As per the official documentation:
@@ -293,9 +275,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
293275
trace!("data count: {dc}");
294276
}
295277

296-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
297-
custom_sections.push(custom_section);
298-
}
278+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
299279

300280
let mut sidetable = Sidetable::new();
301281
let func_blocks_stps = handle_section(&mut wasm, &mut header, SectionTy::Code, |wasm, h| {
@@ -326,9 +306,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
326306
return Err(ValidationError::FunctionAndCodeSectionsHaveDifferentLengths);
327307
}
328308

329-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
330-
custom_sections.push(custom_section);
331-
}
309+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
332310

333311
let data_section = handle_section(&mut wasm, &mut header, SectionTy::Data, |wasm, h| {
334312
// wasm.read_vec(DataSegment::read)
@@ -344,9 +322,7 @@ pub fn validate(wasm: &[u8]) -> Result<ValidationInfo<'_>, ValidationError> {
344322
}
345323
}
346324

347-
while let Some(custom_section) = try_read_custom_section(&mut wasm, &mut header)? {
348-
custom_sections.push(custom_section);
349-
}
325+
read_all_custom_sections(&mut wasm, &mut header, &mut custom_sections)?;
350326

351327
// All sections should have been handled
352328
if let Some(header) = header {
@@ -408,37 +384,27 @@ where
408384
}
409385
}
410386

411-
fn try_read_custom_section<'wasm>(
387+
/// Reads the next sections as long as they are custom sections and pushes them
388+
/// into the `custom_sections` vector.
389+
fn read_all_custom_sections<'wasm>(
412390
wasm: &mut WasmReader<'wasm>,
413391
section_header: &mut Option<SectionHeader>,
414-
) -> Result<Option<(&'wasm str, &'wasm [u8])>, ValidationError> {
415-
handle_section(wasm, section_header, SectionTy::Custom, |wasm, h| {
416-
// customsec ::= section_0(custom)
417-
// custom ::= name byte*
418-
// name ::= b*:vec(byte) => name (if utf8(name) = b*)
419-
// vec(B) ::= n:u32 (x:B)^n => x^n
420-
let name = wasm.read_name()?;
421-
422-
let section_start = wasm.pc;
423-
let section_end = h
424-
.contents
425-
.from()
426-
.checked_add(h.contents.len())
427-
.ok_or(ValidationError::InvalidCustomSectionLength)?;
428-
429-
let contents = wasm
430-
.full_wasm_binary
431-
.get(section_start..section_end)
432-
.ok_or(ValidationError::InvalidCustomSectionLength)?;
433-
434-
let section_len = section_end
435-
.checked_sub(section_start)
436-
.expect("section start <= section end always");
437-
438-
wasm.skip(section_len)?;
439-
440-
Ok((name, contents))
441-
})
392+
custom_sections: &mut Vec<CustomSection<'wasm>>,
393+
) -> Result<(), ValidationError> {
394+
let mut read_custom_section = || {
395+
handle_section(
396+
wasm,
397+
section_header,
398+
SectionTy::Custom,
399+
CustomSection::read_and_validate,
400+
)
401+
};
402+
403+
while let Some(custom_section) = read_custom_section()? {
404+
custom_sections.push(custom_section);
405+
}
406+
407+
Ok(())
442408
}
443409

444410
impl<'wasm> ValidationInfo<'wasm> {
@@ -481,7 +447,7 @@ impl<'wasm> ValidationInfo<'wasm> {
481447
/// Returns a list of all custom sections in the bytecode. Every custom
482448
/// section consists of its name and the custom section's bytecode
483449
/// (excluding the name itself).
484-
pub fn custom_sections(&self) -> &[(&'wasm str, &'wasm [u8])] {
450+
pub fn custom_sections(&self) -> &[CustomSection<'wasm>] {
485451
&self.custom_sections
486452
}
487453
}

0 commit comments

Comments
 (0)