wasm/core/decoding/modules/
code_section.rs

1use alloc::vec::Vec;
2use core::iter;
3
4use crate::{
5    core::{decoding::reader::WasmDecoder, utils::ToUsizeExt},
6    DecodingError, ValType,
7};
8
9pub fn decode_locals(wasm: &mut WasmDecoder) -> Result<Vec<ValType>, DecodingError> {
10    let locals = wasm.decode_vec(|wasm| {
11        let n = wasm.decode_var_u32()?.into_usize();
12        let valtype = ValType::decode(wasm)?;
13
14        Ok((n, valtype))
15    })?;
16
17    // these checks are related to the official test suite binary.wast file, the first 2 assert_malformed's starting at line 350
18    // we check to not have more than 2^32-1 locals, and if that number is okay, we then get to instantiate them all
19    // this is because the flat_map and collect take an insane amount of time
20    // in total, these 2 tests take more than 240s
21    let mut total_no_of_locals: u64 = 0;
22    for local in &locals {
23        let temp = local.0 as u64;
24        if temp > u32::MAX.into() {
25            return Err(DecodingError::TooManyLocals(total_no_of_locals));
26        };
27        total_no_of_locals = match total_no_of_locals.checked_add(temp) {
28            None => return Err(DecodingError::TooManyLocals(total_no_of_locals)),
29            Some(n) => n,
30        }
31    }
32
33    if total_no_of_locals > u32::MAX.into() {
34        return Err(DecodingError::TooManyLocals(total_no_of_locals));
35    }
36
37    // Flatten local types for easier representation where n > 1
38    let locals = locals
39        .into_iter()
40        .flat_map(|entry| iter::repeat_n(entry.1, entry.0))
41        .collect::<Vec<ValType>>();
42
43    Ok(locals)
44}