Skip to main content

wasefire_interpreter/
valid.rs

1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use alloc::collections::BTreeSet;
16use alloc::vec;
17use alloc::vec::Vec;
18use core::cmp::Ordering;
19use core::fmt::Debug;
20use core::marker::PhantomData;
21
22use crate::cursor::*;
23use crate::error::*;
24use crate::format::custom_section;
25use crate::side_table::*;
26use crate::syntax::*;
27use crate::toctou::*;
28use crate::*;
29
30/// Checks whether a WASM module in binary format is valid, and returns it with its side table.
31pub fn prepare(binary: &[u8]) -> Result<Vec<u8>, Error> {
32    let side_table = validate::<Prepare>(binary)?;
33    let mut wasm = vec![];
34    wasm.extend_from_slice(&binary[0 .. 8]);
35    custom_section(&mut wasm, SECTION_NAME, &side_table);
36    wasm.extend_from_slice(&binary[8 ..]);
37    Ok(wasm)
38}
39
40/// Checks whether a WASM module with the side table in binary format is valid.
41pub fn verify(binary: &[u8]) -> Result<(), Error> {
42    validate::<Verify>(binary)
43}
44
45fn validate<M: ValidMode>(binary: &[u8]) -> Result<M::Result, Error> {
46    Context::<M>::default().check_module(&mut Parser::new(binary))
47}
48
49trait ValidMode: Default {
50    type Branches: BranchesApi;
51    type BranchTable<'a, 'm>: BranchTableApi<'m>;
52    type SideTable<'m>: Debug;
53    type Result: Debug;
54
55    fn parse_side_table<'m>(parser: &mut Parser<'m>) -> Result<Self::SideTable<'m>, Error>;
56    fn next_branch_table<'a, 'm>(
57        side_table: &'a mut Self::SideTable<'m>, type_idx: usize, parser_state: CursorState,
58    ) -> Result<Self::BranchTable<'a, 'm>, Error>;
59    fn side_table_result(side_table: Self::SideTable<'_>) -> Result<Self::Result, Error>;
60}
61
62trait BranchesApi: Debug + Default + IntoIterator<Item = SideTableBranch> {
63    fn push_branch(&mut self, branch: SideTableBranch) -> CheckResult;
64}
65
66trait BranchTableApi<'m>: Debug {
67    fn stitch_branch(&mut self, source: SideTableBranch, target: SideTableBranch) -> CheckResult;
68    fn patch_branch(&self, source: SideTableBranch) -> Result<SideTableBranch, Error>;
69    fn allocate_branch(&mut self);
70    fn next_index(&self) -> usize;
71}
72
73#[derive(Default)]
74struct Prepare;
75impl ValidMode for Prepare {
76    /// List of source branches.
77    type Branches = Vec<SideTableBranch>;
78    type BranchTable<'a, 'm> = &'a mut Vec<BranchTableEntry>;
79    type SideTable<'m> = Vec<MetadataEntry>;
80    type Result = Vec<u8>;
81
82    fn parse_side_table<'m>(_: &mut Parser<'m>) -> Result<Self::SideTable<'m>, Error> {
83        Ok(Vec::new())
84    }
85
86    fn next_branch_table<'a, 'm>(
87        side_tables: &'a mut Self::SideTable<'m>, type_idx: usize, parser_state: CursorState,
88    ) -> Result<Self::BranchTable<'a, 'm>, Error> {
89        side_tables.push(MetadataEntry { type_idx, parser_state, branch_table: vec![] });
90        Ok(&mut side_tables.last_mut().unwrap().branch_table)
91    }
92
93    fn side_table_result(side_table: Self::SideTable<'_>) -> Result<Self::Result, Error> {
94        serialize(&side_table)
95    }
96}
97
98impl BranchesApi for Vec<SideTableBranch> {
99    fn push_branch(&mut self, branch: SideTableBranch) -> CheckResult {
100        Ok(self.push(branch))
101    }
102}
103
104impl<'m> BranchTableApi<'m> for &mut Vec<BranchTableEntry> {
105    /// Updates the branch table for source according to target
106    fn stitch_branch(&mut self, source: SideTableBranch, target: SideTableBranch) -> CheckResult {
107        let delta_ip = delta(source, target, |x| x.parser as isize)?;
108        let delta_stp = delta(source, target, |x| x.branch_table as isize)?;
109        let val_cnt = u32::try_from(target.values).map_err(|_| side_table_unsupported())?;
110        let pop_cnt = source.stack.checked_sub(target.stack).ok_or_else(invalid)?;
111        let pop_cnt = u32::try_from(pop_cnt).map_err(|_| side_table_unsupported())?;
112        debug_assert!(self[source.branch_table].is_invalid());
113        self[source.branch_table] =
114            BranchTableEntry::new(BranchTableEntryView { delta_ip, delta_stp, val_cnt, pop_cnt })?;
115        Ok(())
116    }
117
118    fn patch_branch(&self, source: SideTableBranch) -> Result<SideTableBranch, Error> {
119        Ok(source)
120    }
121
122    fn allocate_branch(&mut self) {
123        self.push(BranchTableEntry::invalid());
124    }
125
126    fn next_index(&self) -> usize {
127        self.len()
128    }
129}
130
131#[derive(Debug)]
132struct MetadataView<'m> {
133    metadata: Metadata<'m>,
134    branch_idx: usize,
135}
136
137#[derive(Debug)]
138struct SideTableVerify<'m> {
139    view: SideTableView<'m>,
140    func_idx: usize,
141}
142
143#[derive(Default)]
144struct Verify;
145impl ValidMode for Verify {
146    /// Contains at most one _target_ branch. Source branches are eagerly patched to
147    /// their target branch using the branch table.
148    type Branches = Option<SideTableBranch>;
149    type BranchTable<'a, 'm> = MetadataView<'m>;
150    type SideTable<'m> = SideTableVerify<'m>;
151    type Result = ();
152
153    fn parse_side_table<'m>(parser: &mut Parser<'m>) -> Result<Self::SideTable<'m>, Error> {
154        Ok(SideTableVerify { view: parser.parse_side_table()?, func_idx: 0 })
155    }
156
157    fn next_branch_table<'a, 'm>(
158        side_table: &'a mut Self::SideTable<'m>, type_idx: usize, parser_state: CursorState,
159    ) -> Result<Self::BranchTable<'a, 'm>, Error> {
160        let metadata = side_table.view.metadata::<Check>(side_table.func_idx)?;
161        side_table.func_idx += 1;
162        check(metadata.type_idx::<Check>()? == type_idx)?;
163        check(metadata.parser_state::<Check>()? == parser_state)?;
164        Ok(MetadataView { metadata, branch_idx: 0 })
165    }
166
167    fn side_table_result(side_table: Self::SideTable<'_>) -> Result<Self::Result, Error> {
168        check((side_table.func_idx + 1) * 2 == side_table.view.indices.len())
169    }
170}
171
172impl BranchesApi for Option<SideTableBranch> {
173    fn push_branch(&mut self, branch: SideTableBranch) -> CheckResult {
174        check(self.replace(branch).is_none_or(|x| x == branch))
175    }
176}
177
178impl<'m> BranchTableApi<'m> for MetadataView<'m> {
179    fn stitch_branch(&mut self, source: SideTableBranch, target: SideTableBranch) -> CheckResult {
180        check(source == target)
181    }
182
183    fn patch_branch(&self, mut source: SideTableBranch) -> Result<SideTableBranch, Error> {
184        let entry = self
185            .metadata
186            .branch_table::<Check>()?
187            .get(source.branch_table)
188            .ok_or_else(invalid)?
189            .view::<Check>()?;
190        source.parser =
191            source.parser.checked_add_signed(entry.delta_ip as isize).ok_or_else(invalid)?;
192        source.branch_table =
193            source.branch_table.checked_add_signed(entry.delta_stp as isize).ok_or_else(invalid)?;
194        source.stack = source.stack.checked_sub(entry.pop_cnt as usize).ok_or_else(invalid)?;
195        source.values = entry.val_cnt as usize;
196        Ok(source)
197    }
198
199    fn allocate_branch(&mut self) {
200        self.branch_idx += 1;
201    }
202
203    fn next_index(&self) -> usize {
204        self.branch_idx
205    }
206}
207
208pub type Parser<'m> = parser::Parser<'m, Check>;
209type CheckResult = MResult<(), Check>;
210
211#[derive(Default)]
212struct Context<'m, M: ValidMode> {
213    types: Vec<FuncType<'m>>,
214    funcs: Vec<TypeIdx>,
215    tables: Vec<TableType>,
216    mems: Vec<MemType>,
217    globals: Vec<GlobalType>,
218    elems: Vec<RefType>,
219    datas: Option<usize>,
220    mode: PhantomData<M>,
221}
222
223impl<'m, M: ValidMode> Context<'m, M> {
224    fn check_module(&mut self, parser: &mut Parser<'m>) -> Result<M::Result, Error> {
225        check(parser.parse_bytes(8)? == b"\0asm\x01\0\0\0")?;
226        let mut side_table = M::parse_side_table(parser)?;
227        parser.shrink();
228        if let Some(mut parser) = self.check_section(parser, SectionId::Type)? {
229            let n = parser.parse_vec()?;
230            self.types.reserve(n);
231            for _ in 0 .. n {
232                self.types.push(parser.parse_functype()?);
233            }
234            check(parser.is_empty())?;
235        }
236        if let Some(mut parser) = self.check_section(parser, SectionId::Import)? {
237            for _ in 0 .. parser.parse_vec()? {
238                self.add_import(&mut parser)?;
239            }
240            check(parser.is_empty())?;
241        }
242        let imported_funcs = self.funcs.len();
243        if let Some(mut parser) = self.check_section(parser, SectionId::Function)? {
244            for _ in 0 .. parser.parse_vec()? {
245                self.add_functype(parser.parse_typeidx()?)?;
246            }
247            check(parser.is_empty())?;
248        }
249        let mut refs = vec![false; self.funcs.len()];
250        if let Some(mut parser) = self.check_section(parser, SectionId::Table)? {
251            for _ in 0 .. parser.parse_vec()? {
252                let saved = parser.save();
253                if parser.parse_bytes(2) == Ok(&[0x40, 0x00]) {
254                    return Err(unsupported(if_debug!(Unsupported::TableInit)));
255                } else {
256                    unsafe { parser.restore(saved) };
257                    self.add_tabletype(parser.parse_tabletype()?)?;
258                }
259            }
260            check(parser.is_empty())?;
261        }
262        if let Some(mut parser) = self.check_section(parser, SectionId::Memory)? {
263            for _ in 0 .. parser.parse_vec()? {
264                self.add_memtype(parser.parse_memtype()?)?;
265            }
266            check(parser.is_empty())?;
267        }
268        check(self.mems.len() <= 1)?;
269        if self.check_section(parser, SectionId::Tag)?.is_some() {
270            return Err(unsupported(if_debug!(Unsupported::Exception)));
271        }
272        if let Some(mut parser) = self.check_section(parser, SectionId::Global)? {
273            for _ in 0 .. parser.parse_vec()? {
274                let g = parser.parse_globaltype()?;
275                Expr::check_const(self, &mut parser, &mut refs, g.value.into())?;
276                self.add_globaltype(g)?;
277            }
278            check(parser.is_empty())?;
279        }
280        if let Some(mut parser) = self.check_section(parser, SectionId::Export)? {
281            let mut names = BTreeSet::new();
282            for _ in 0 .. parser.parse_vec()? {
283                let name = parser.parse_name()?;
284                check(names.insert(name))?;
285                let desc = parser.parse_exportdesc()?;
286                self.check_exportdesc(&desc)?;
287                if let ExportDesc::Func(x) = desc {
288                    refs[x as usize] = true;
289                }
290            }
291            check(parser.is_empty())?;
292        }
293        if let Some(mut parser) = self.check_section(parser, SectionId::Start)? {
294            let x = parser.parse_funcidx()?;
295            let t = self.functype(x)?;
296            check(t.params.is_empty() && t.results.is_empty())?;
297            check(parser.is_empty())?;
298        }
299        if let Some(mut parser) = self.check_section(parser, SectionId::Element)? {
300            for _ in 0 .. parser.parse_vec()? {
301                parser.parse_elem(&mut ParseElem::new(self, &mut refs))?;
302            }
303            check(parser.is_empty())?;
304        }
305        if let Some(mut parser) = self.check_section(parser, SectionId::DataCount)? {
306            self.datas = Some(parser.parse_u32()? as usize);
307            check(parser.is_empty())?;
308        }
309        if let Some(mut parser) = self.check_section(parser, SectionId::Code)? {
310            check(self.funcs.len() == imported_funcs + parser.parse_vec()?)?;
311            for x in imported_funcs .. self.funcs.len() {
312                let size = parser.parse_u32()? as usize;
313                let mut parser = parser.split_at(size)?;
314                let parser_state = parser.save();
315                let t = self.functype(x as FuncIdx).unwrap();
316                let mut locals = t.params.to_vec();
317                parser.parse_locals(&mut locals)?;
318                let branch_table =
319                    M::next_branch_table(&mut side_table, self.funcs[x] as usize, parser_state)?;
320                Expr::check_body(self, &mut parser, &refs, locals, t.results, branch_table)?;
321                check(parser.is_empty())?;
322            }
323            check(parser.is_empty())?;
324        } else {
325            check(self.funcs.len() == imported_funcs)?;
326        }
327        if let Some(mut parser) = self.check_section(parser, SectionId::Data)? {
328            let n = parser.parse_vec()?;
329            check(self.datas.is_none_or(|m| m == n))?;
330            for _ in 0 .. n {
331                parser.parse_data(&mut ParseData::new(self, &mut refs))?;
332            }
333            check(parser.is_empty())?;
334        } else {
335            check(self.datas.is_none_or(|m| m == 0))?;
336        }
337        self.check_section(parser, SectionId::Custom)?;
338        check(parser.is_empty())?;
339        M::side_table_result(side_table)
340    }
341
342    fn check_section(
343        &mut self, parser: &mut Parser<'m>, expected_id: SectionId,
344    ) -> Result<Option<Parser<'m>>, Error> {
345        let (actual_id, next_parser) = loop {
346            if parser.is_empty() {
347                return Ok(None);
348            }
349            let mut next_parser = parser.clone();
350            let id = next_parser.parse_section_id()?;
351            if id != SectionId::Custom {
352                break (id, next_parser);
353            }
354            *parser = next_parser;
355            let mut section = parser.split_section()?;
356            section.parse_name()?;
357            // We ignore the remaining bytes.
358        };
359        match expected_id.order().cmp(&actual_id.order()) {
360            Ordering::Less => Ok(None),
361            Ordering::Equal => {
362                *parser = next_parser;
363                Ok(Some(parser.split_section()?))
364            }
365            Ordering::Greater => Err(invalid()),
366        }
367    }
368
369    fn add_import(&mut self, parser: &mut Parser) -> CheckResult {
370        parser.parse_name()?;
371        parser.parse_name()?;
372        match parser.parse_importdesc()? {
373            ImportDesc::Func(x) => self.add_functype(x),
374            ImportDesc::Table(t) => self.add_tabletype(t),
375            ImportDesc::Mem(m) => self.add_memtype(m),
376            ImportDesc::Global(g) => self.add_globaltype(g),
377        }
378    }
379
380    fn add_functype(&mut self, x: TypeIdx) -> CheckResult {
381        check((x as usize) < self.types.len())?;
382        self.funcs.push(x);
383        Ok(())
384    }
385
386    fn add_tabletype(&mut self, t: TableType) -> CheckResult {
387        check(t.limits.valid(TABLE_MAX))?;
388        self.tables.push(t);
389        Ok(())
390    }
391
392    fn add_memtype(&mut self, m: MemType) -> CheckResult {
393        check(m.valid(MEM_MAX))?;
394        self.mems.push(m);
395        Ok(())
396    }
397
398    fn add_globaltype(&mut self, g: GlobalType) -> CheckResult {
399        self.globals.push(g);
400        Ok(())
401    }
402
403    fn check_exportdesc(&self, desc: &ExportDesc) -> CheckResult {
404        let (&x, n) = match desc {
405            ExportDesc::Func(x) => (x, self.funcs.len()),
406            ExportDesc::Table(x) => (x, self.tables.len()),
407            ExportDesc::Mem(x) => (x, self.mems.len()),
408            ExportDesc::Global(x) => (x, self.globals.len()),
409        };
410        check((x as usize) < n)
411    }
412
413    fn type_(&self, x: TypeIdx) -> Result<FuncType<'m>, Error> {
414        self.types.get(x as usize).cloned().ok_or_else(invalid)
415    }
416
417    fn functype(&self, x: FuncIdx) -> Result<FuncType<'m>, Error> {
418        self.type_(*self.funcs.get(x as usize).ok_or_else(invalid)?)
419    }
420
421    fn table(&self, x: TableIdx) -> Result<&TableType, Error> {
422        self.tables.get(x as usize).ok_or_else(invalid)
423    }
424
425    fn mem(&self, x: MemIdx) -> Result<&MemType, Error> {
426        self.mems.get(x as usize).ok_or_else(invalid)
427    }
428
429    fn global(&self, x: GlobalIdx) -> Result<&GlobalType, Error> {
430        self.globals.get(x as usize).ok_or_else(invalid)
431    }
432
433    fn elem(&self, x: ElemIdx) -> Result<RefType, Error> {
434        self.elems.get(x as usize).cloned().ok_or_else(invalid)
435    }
436
437    fn data(&self, x: DataIdx) -> CheckResult {
438        check(self.datas.is_some_and(|n| (x as usize) < n))
439    }
440}
441
442struct ParseElem<'a, 'm, M: ValidMode> {
443    context: &'a mut Context<'m, M>,
444    refs: &'a mut [bool],
445    table_type: OpdType,
446    elem_type: RefType,
447}
448
449impl<'a, 'm, M: ValidMode> ParseElem<'a, 'm, M> {
450    fn new(context: &'a mut Context<'m, M>, refs: &'a mut [bool]) -> Self {
451        Self { context, refs, table_type: OpdType::Bottom, elem_type: RefType::FuncRef }
452    }
453}
454
455impl<'m, M: ValidMode> parser::ParseElem<'m, Check> for ParseElem<'_, 'm, M> {
456    fn mode(&mut self, mode: parser::ElemMode<'_, 'm, Check>) -> MResult<(), Check> {
457        if let parser::ElemMode::Active { table, offset } = mode {
458            Expr::check_const(self.context, offset, self.refs, ValType::I32.into())?;
459            self.table_type = self.context.table(table)?.item.into();
460        }
461        Ok(())
462    }
463
464    fn type_(&mut self, type_: RefType) -> MResult<(), Check> {
465        self.elem_type = type_;
466        check(self.table_type.matches(type_.into()))?;
467        self.context.elems.push(type_);
468        Ok(())
469    }
470
471    fn init_funcidx(&mut self, x: FuncIdx) -> MResult<(), Check> {
472        check((x as usize) < self.context.funcs.len())?;
473        self.refs[x as usize] = true;
474        Ok(())
475    }
476
477    fn init_expr(&mut self, parser: &mut parser::Parser<'m, Check>) -> MResult<(), Check> {
478        Expr::check_const(self.context, parser, self.refs, ValType::from(self.elem_type).into())
479    }
480}
481
482struct ParseData<'a, 'm, M: ValidMode> {
483    context: &'a mut Context<'m, M>,
484    refs: &'a mut [bool],
485}
486
487impl<'a, 'm, M: ValidMode> ParseData<'a, 'm, M> {
488    fn new(context: &'a mut Context<'m, M>, refs: &'a mut [bool]) -> Self {
489        Self { context, refs }
490    }
491}
492
493impl<'m, M: ValidMode> parser::ParseData<'m, Check> for ParseData<'_, 'm, M> {
494    fn mode(&mut self, mode: parser::DataMode<'_, 'm, Check>) -> MResult<(), Check> {
495        if let parser::DataMode::Active { memory, offset } = mode {
496            self.context.mem(memory)?;
497            Expr::check_const(self.context, offset, self.refs, ValType::I32.into())?;
498        }
499        Ok(())
500    }
501}
502
503#[derive(Debug, Copy, Clone, PartialEq, Eq)]
504#[repr(u8)]
505enum OpdType {
506    Bottom = 0x80,
507    I32 = 0x7f,
508    I64 = 0x7e,
509    F32 = 0x7d,
510    F64 = 0x7c,
511    V128 = 0x7b,
512    FuncRef = 0x70,
513    ExternRef = 0x6f,
514}
515
516macro_rules! impl_type_conv {
517    ($from:ident => $to:ident [$($val:ident)*]) => {
518        impl From<$from> for $to {
519            fn from(x: $from) -> $to {
520                match x {
521                    $($from::$val => $to::$val),*
522                }
523            }
524        }
525    };
526}
527impl_type_conv!(NumType => ValType [I32 I64 F32 F64]);
528impl_type_conv!(RefType => ValType [FuncRef ExternRef]);
529impl_type_conv!(NumType => OpdType [I32 I64 F32 F64]);
530impl_type_conv!(RefType => OpdType [FuncRef ExternRef]);
531impl_type_conv!(ValType => OpdType [I32 I64 F32 F64 V128 FuncRef ExternRef]);
532
533impl OpdType {
534    fn matches(self, other: ValType) -> bool {
535        self == OpdType::Bottom || self == other.into()
536    }
537
538    fn unify(self, other: OpdType) -> Result<OpdType, Error> {
539        match (self, other) {
540            (OpdType::Bottom, x) | (x, OpdType::Bottom) => Ok(x),
541            (x, y) if x == y => Ok(x),
542            _ => Err(invalid()),
543        }
544    }
545
546    fn is_num(self) -> bool {
547        matches!(self, OpdType::Bottom | OpdType::I32 | OpdType::I64 | OpdType::F32 | OpdType::F64)
548    }
549
550    fn is_vec(self) -> bool {
551        matches!(self, OpdType::Bottom | OpdType::V128)
552    }
553
554    fn is_ref(self) -> bool {
555        matches!(self, OpdType::Bottom | OpdType::FuncRef | OpdType::ExternRef)
556    }
557}
558
559struct Expr<'a, 'm, M: ValidMode> {
560    context: &'a Context<'m, M>,
561    parser: &'a mut Parser<'m>,
562    /// Whether the expression is const and the function references.
563    is_const: Result<&'a mut [bool], &'a [bool]>,
564    is_body: bool,
565    locals: Vec<ValType>,
566    labels: Vec<Label<'m, M>>,
567    branch_table: Option<M::BranchTable<'a, 'm>>,
568}
569
570#[derive(Debug, Copy, Clone, PartialEq, Eq)]
571struct SideTableBranch {
572    parser: usize,
573    branch_table: usize,
574    /// Function stack length (including branch values).
575    stack: usize,
576    /// Branch values (only for target branches, zero for source branches).
577    values: usize,
578}
579
580#[derive(Debug, Default)]
581struct Label<'m, M: ValidMode> {
582    type_: FuncType<'m>,
583    /// Whether an `else` is possible before `end`.
584    kind: LabelKind,
585    /// Whether the bottom of the stack is polymorphic.
586    polymorphic: bool,
587    stack: Vec<OpdType>,
588    branches: M::Branches,
589    /// Function stack length up to this label (excluding branch values).
590    prev_stack: usize,
591}
592
593#[derive(Debug, Default, Clone)]
594enum LabelKind {
595    #[default]
596    Block,
597    Loop(SideTableBranch),
598    If(Option<SideTableBranch>),
599}
600
601impl<'a, 'm, M: ValidMode> Expr<'a, 'm, M> {
602    fn new(
603        context: &'a Context<'m, M>, parser: &'a mut Parser<'m>,
604        is_const: Result<&'a mut [bool], &'a [bool]>, branch_table: Option<M::BranchTable<'a, 'm>>,
605    ) -> Self {
606        Self {
607            context,
608            parser,
609            is_const,
610            is_body: false,
611            locals: vec![],
612            labels: vec![Label::default()],
613            branch_table,
614        }
615    }
616
617    fn check_const(
618        context: &'a Context<'m, M>, parser: &'a mut Parser<'m>, refs: &'a mut [bool],
619        expected: ResultType<'m>,
620    ) -> CheckResult {
621        let mut expr = Expr::new(context, parser, Ok(refs), None);
622        expr.label().type_.results = expected;
623        expr.check()
624    }
625
626    fn check_body(
627        context: &'a Context<'m, M>, parser: &'a mut Parser<'m>, refs: &'a [bool],
628        locals: Vec<ValType>, results: ResultType<'m>, branch_table: M::BranchTable<'a, 'm>,
629    ) -> CheckResult {
630        let mut expr = Expr::new(context, parser, Err(refs), Some(branch_table));
631        expr.is_body = true;
632        expr.locals = locals;
633        expr.label().type_.results = results;
634        expr.check()
635    }
636
637    fn check(&mut self) -> CheckResult {
638        while !self.labels.is_empty() {
639            self.instr()?;
640        }
641        Ok(())
642    }
643
644    fn instr(&mut self) -> CheckResult {
645        use Instr::*;
646        let saved = self.parser.save().start();
647        let instr = self.parser.parse_instr()?;
648        if matches!(instr, End) {
649            return self.end_label();
650        }
651        if self.is_const.is_ok() {
652            use crate::syntax::IBinOp;
653            match instr {
654                GlobalGet(x) => check(self.context.global(x)?.mutable == Mut::Const)?,
655                I32Const(_) => (),
656                I64Const(_) => (),
657                #[cfg(feature = "float-types")]
658                F32Const(_) => (),
659                #[cfg(feature = "float-types")]
660                F64Const(_) => (),
661                RefNull(_) => (),
662                RefFunc(_) => (),
663                Instr::IBinOp(_, IBinOp::Add | IBinOp::Sub | IBinOp::Mul) => (),
664                _ => return Err(invalid()),
665            }
666        }
667        match instr {
668            Unreachable => self.stack_polymorphic(),
669            Nop => (),
670            Block(b) => self.push_label(self.blocktype(&b)?, LabelKind::Block)?,
671            Loop(b) => {
672                let type_ = self.blocktype(&b)?;
673                let mut target = self.branch_target(type_.params.len());
674                target.parser = saved;
675                target.stack +=
676                    self.stack().len().checked_sub(target.values).ok_or_else(invalid)?;
677                self.push_label(type_, LabelKind::Loop(target))?
678            }
679            If(b) => {
680                self.pop_check(ValType::I32)?;
681                let branch = self.branch_source();
682                self.push_label(self.blocktype(&b)?, LabelKind::If(branch))?;
683            }
684            Else => {
685                self.br_label(0)?;
686                let FuncType { params, results } = self.label().type_;
687                self.pops(results)?;
688                check(self.stack().is_empty())?;
689                self.label().polymorphic = false;
690                self.pushs(params);
691                match core::mem::replace(&mut self.label().kind, LabelKind::Block) {
692                    LabelKind::If(None) => (),
693                    LabelKind::If(Some(source)) => {
694                        let source = M::BranchTable::patch_branch(
695                            self.branch_table.as_ref().unwrap(),
696                            source,
697                        )?;
698                        let target = self.branch_target(params.len());
699                        self.branch_table.as_mut().unwrap().stitch_branch(source, target)?;
700                    }
701                    _ => Err(invalid())?,
702                }
703            }
704            End => unreachable!(),
705            Br(l) => {
706                let res = self.br_label(l)?;
707                self.pops(res)?;
708                self.stack_polymorphic();
709            }
710            BrIf(l) => {
711                self.pop_check(ValType::I32)?;
712                let res = self.br_label(l)?;
713                self.swaps(res)?;
714            }
715            BrTable(ls, ln) => {
716                self.pop_check(ValType::I32)?;
717                let tn = self.br_label(ln)?;
718                self.peeks(tn)?;
719                for l in ls {
720                    let t = self.br_label(l)?;
721                    check(tn.len() == t.len())?;
722                    self.peeks(t)?;
723                }
724                self.stack_polymorphic();
725            }
726            Return => {
727                check(self.is_body)?;
728                self.pops(self.labels[0].type_.results)?;
729                self.stack_polymorphic();
730            }
731            Call(x) => self.call(self.context.functype(x)?)?,
732            CallIndirect(x, y) => {
733                check(self.context.table(x)?.item == RefType::FuncRef)?;
734                self.pop_check(ValType::I32)?;
735                self.call(self.context.type_(y)?)?;
736            }
737            Drop => drop(self.pop()?),
738            Select(None) => {
739                self.pop_check(ValType::I32)?;
740                let t = self.pop()?.unify(self.pop()?)?;
741                check(t.is_num() || t.is_vec())?;
742                self.push(t);
743            }
744            Select(Some(t)) => {
745                check(t.len() == 1)?;
746                self.pops([t[0], t[0], ValType::I32][..].into())?;
747                self.pushs(t[0].into());
748            }
749            LocalGet(x) => self.push(self.local(x)?.into()),
750            LocalSet(x) => self.pop_check(self.local(x)?)?,
751            LocalTee(x) => self.swap(self.local(x)?)?,
752            GlobalGet(x) => self.push(self.context.global(x)?.value.into()),
753            GlobalSet(x) => {
754                let g = self.context.global(x)?;
755                check(g.mutable == Mut::Var)?;
756                self.pop_check(g.value)?;
757            }
758            TableGet(x) => {
759                self.pop_check(ValType::I32)?;
760                self.push(self.context.table(x)?.item.into());
761            }
762            TableSet(x) => {
763                self.pops([ValType::I32, self.context.table(x)?.item.into()][..].into())?;
764            }
765            ILoad(n, m) => self.load(false, NumType::i(n), n.into(), m)?,
766            #[cfg(feature = "float-types")]
767            FLoad(n, m) => self.load(false, NumType::f(n), n.into(), m)?,
768            ILoad_(b, _, m) => self.load(false, NumType::i(b.into()), b.into(), m)?,
769            IStore(n, m) => self.store(false, NumType::i(n), n.into(), m)?,
770            #[cfg(feature = "float-types")]
771            FStore(n, m) => self.store(false, NumType::f(n), n.into(), m)?,
772            IStore_(b, m) => self.store(false, NumType::i(b.into()), b.into(), m)?,
773            MemorySize => {
774                check(!self.context.mems.is_empty())?;
775                self.push(OpdType::I32);
776            }
777            MemoryGrow => {
778                check(!self.context.mems.is_empty())?;
779                self.swap(ValType::I32)?;
780            }
781            I32Const(_) => self.push(OpdType::I32),
782            I64Const(_) => self.push(OpdType::I64),
783            #[cfg(feature = "float-types")]
784            F32Const(_) => self.push(OpdType::F32),
785            #[cfg(feature = "float-types")]
786            F64Const(_) => self.push(OpdType::F64),
787            ITestOp(n, _) => self.testop(NumType::i(n))?,
788            IRelOp(n, _) => self.relop(NumType::i(n))?,
789            #[cfg(feature = "float-types")]
790            FRelOp(n, _) => self.relop(NumType::f(n))?,
791            IUnOp(n, _) => self.unop(NumType::i(n))?,
792            #[cfg(feature = "float-types")]
793            FUnOp(n, _) => self.unop(NumType::f(n))?,
794            IBinOp(n, _) => self.binop(NumType::i(n))?,
795            #[cfg(feature = "float-types")]
796            FBinOp(n, _) => self.binop(NumType::f(n))?,
797            CvtOp(op) => self.cvtop(op.dst(), op.src())?,
798            IExtend(b) => self.unop(NumType::i(b.into()))?,
799            RefNull(t) => self.push(t.into()),
800            RefIsNull => {
801                check(self.pop()?.is_ref())?;
802                self.push(OpdType::I32);
803            }
804            RefFunc(x) => {
805                check((x as usize) < self.context.funcs.len())?;
806                match &mut self.is_const {
807                    Ok(refs) => refs[x as usize] = true,
808                    Err(refs) => check(refs[x as usize])?,
809                }
810                self.push(OpdType::FuncRef);
811            }
812            MemoryInit(x) => {
813                check(!self.context.mems.is_empty())?;
814                self.context.data(x)?;
815                self.pops([ValType::I32; 3][..].into())?;
816            }
817            DataDrop(x) => self.context.data(x)?,
818            MemoryCopy | MemoryFill => {
819                check(!self.context.mems.is_empty())?;
820                self.pops([ValType::I32; 3][..].into())?;
821            }
822            TableInit(x, y) => {
823                check(self.context.table(x)?.item == self.context.elem(y)?)?;
824                self.pops([ValType::I32; 3][..].into())?;
825            }
826            ElemDrop(x) => drop(self.context.elem(x)?),
827            TableCopy(x, y) => {
828                check(self.context.table(x)?.item == self.context.table(y)?.item)?;
829                self.pops([ValType::I32; 3][..].into())?;
830            }
831            TableGrow(x) => {
832                let t = self.context.table(x)?.item;
833                self.pops([t.into(), ValType::I32][..].into())?;
834                self.push(OpdType::I32);
835            }
836            TableSize(x) => {
837                self.context.table(x)?;
838                self.push(OpdType::I32);
839            }
840            TableFill(x) => {
841                let t = self.context.table(x)?.item;
842                self.pops([ValType::I32, t.into(), ValType::I32][..].into())?;
843            }
844        }
845        Ok(())
846    }
847
848    fn blocktype(&self, b: &BlockType) -> Result<FuncType<'m>, Error> {
849        Ok(match *b {
850            BlockType::None => FuncType { params: ().into(), results: ().into() },
851            BlockType::Type(t) => FuncType { params: ().into(), results: t.into() },
852            BlockType::Index(x) => self.context.type_(x)?,
853        })
854    }
855
856    fn local(&self, x: LocalIdx) -> Result<ValType, Error> {
857        self.locals.get(x as usize).cloned().ok_or_else(invalid)
858    }
859
860    fn label(&mut self) -> &mut Label<'m, M> {
861        self.labels.last_mut().unwrap()
862    }
863
864    fn immutable_label(&self) -> &Label<'m, M> {
865        self.labels.last().unwrap()
866    }
867
868    fn stack(&mut self) -> &mut Vec<OpdType> {
869        &mut self.label().stack
870    }
871
872    fn push(&mut self, t: OpdType) {
873        self.stack().push(t);
874    }
875
876    fn pushs(&mut self, values: ResultType) {
877        self.stack().extend(values.iter().cloned().map(OpdType::from));
878    }
879
880    fn pop(&mut self) -> Result<OpdType, Error> {
881        let label = self.label();
882        Ok(match label.stack.pop() {
883            Some(x) => x,
884            None => {
885                check(label.polymorphic)?;
886                OpdType::Bottom
887            }
888        })
889    }
890
891    fn pop_check(&mut self, expected: ValType) -> CheckResult {
892        check(self.pop()?.matches(expected))
893    }
894
895    fn pops(&mut self, expected: ResultType) -> CheckResult {
896        for &y in expected.iter().rev() {
897            check(self.pop()?.matches(y))?;
898        }
899        Ok(())
900    }
901
902    fn swap(&mut self, t: ValType) -> CheckResult {
903        self.pop_check(t)?;
904        self.push(t.into());
905        Ok(())
906    }
907
908    fn for_each(
909        &mut self, expected: ResultType, mut f: impl FnMut(&mut OpdType, ValType) -> CheckResult,
910    ) -> CheckResult {
911        let label = self.label();
912        if label.stack.len() < expected.len() {
913            check(label.polymorphic)?;
914            let k = expected.len() - label.stack.len();
915            label.stack.resize(expected.len(), OpdType::Bottom);
916            label.stack.rotate_right(k);
917        }
918        let n = label.stack.len() - expected.len();
919        for (x, &y) in label.stack[n ..].iter_mut().zip(expected.iter()) {
920            f(x, y)?;
921        }
922        Ok(())
923    }
924
925    fn swaps(&mut self, expected: ResultType) -> CheckResult {
926        #[allow(clippy::unit_arg)]
927        self.for_each(expected, |x, y| Ok(*x = x.unify(y.into())?))
928    }
929
930    fn peeks(&mut self, expected: ResultType) -> CheckResult {
931        self.for_each(expected, |x, y| check(x.matches(y)))
932    }
933
934    fn push_label(&mut self, type_: FuncType<'m>, kind: LabelKind) -> CheckResult {
935        self.pops(type_.params)?;
936        let stack = type_.params.iter().cloned().map(OpdType::from).collect();
937        let prev_label = self.immutable_label();
938        let prev_stack = prev_label.prev_stack + prev_label.stack.len();
939        let label = Label {
940            type_,
941            kind,
942            polymorphic: false,
943            stack,
944            branches: Default::default(),
945            prev_stack,
946        };
947        self.labels.push(label);
948        Ok(())
949    }
950
951    fn end_label(&mut self) -> CheckResult {
952        let branches = core::mem::take(&mut self.label().branches);
953        if self.is_const.is_ok() {
954            assert_eq!(branches.into_iter().count(), 0);
955            assert!(matches!(self.label().kind, LabelKind::Block));
956        } else {
957            let results_len = self.label().type_.results.len();
958            let mut target = self.branch_target(results_len);
959            for source in branches {
960                self.branch_table.as_mut().unwrap().stitch_branch(source, target)?;
961            }
962            let label = self.label();
963            if let LabelKind::If(source) = label.kind {
964                check(label.type_.params == label.type_.results)?;
965                if let Some(source) = source {
966                    let source = self.branch_table.as_ref().unwrap().patch_branch(source)?;
967                    // This function is only called after parsing an End instruction.
968                    target.parser -= 1;
969                    self.branch_table.as_mut().unwrap().stitch_branch(source, target)?;
970                }
971            }
972        }
973        let results = self.label().type_.results;
974        self.pops(results)?;
975        check(self.labels.pop().unwrap().stack.is_empty())?;
976        if !self.labels.is_empty() {
977            self.pushs(results);
978        }
979        Ok(())
980    }
981
982    fn br_label(&mut self, l: LabelIdx) -> Result<ResultType<'m>, Error> {
983        let l = l as usize;
984        let n = self.labels.len();
985        check(l < n)?;
986        let source = match self.branch_source() {
987            None => None,
988            Some(x) => Some(self.branch_table.as_ref().unwrap().patch_branch(x)?),
989        };
990        let label = &mut self.labels[n - l - 1];
991        Ok(match label.kind {
992            LabelKind::Block | LabelKind::If(_) => {
993                if let Some(source) = source {
994                    label.branches.push_branch(source)?;
995                }
996                label.type_.results
997            }
998            LabelKind::Loop(target) => {
999                if let Some(source) = source {
1000                    self.branch_table.as_mut().unwrap().stitch_branch(source, target)?;
1001                }
1002                label.type_.params
1003            }
1004        })
1005    }
1006
1007    fn branch_source(&mut self) -> Option<SideTableBranch> {
1008        if self.label().polymorphic {
1009            // We don't need a branch table entry for unreachable code.
1010            return None;
1011        }
1012        let mut branch = self.branch();
1013        branch.stack += self.stack().len();
1014        self.branch_table.as_mut().unwrap().allocate_branch();
1015        Some(branch)
1016    }
1017
1018    fn branch_target(&self, values: usize) -> SideTableBranch {
1019        let mut branch = self.branch();
1020        branch.stack += values;
1021        branch.values = values;
1022        branch
1023    }
1024
1025    fn branch(&self) -> SideTableBranch {
1026        SideTableBranch {
1027            parser: self.parser.save().start(),
1028            branch_table: self.branch_table.as_ref().unwrap().next_index(),
1029            stack: self.immutable_label().prev_stack,
1030            values: 0,
1031        }
1032    }
1033
1034    fn call(&mut self, t: FuncType) -> CheckResult {
1035        self.pops(t.params)?;
1036        self.pushs(t.results);
1037        Ok(())
1038    }
1039
1040    fn stack_polymorphic(&mut self) {
1041        let label = self.label();
1042        label.stack.clear();
1043        label.polymorphic = true;
1044    }
1045
1046    fn load(&mut self, aligned: bool, t: NumType, n: usize, m: MemArg) -> CheckResult {
1047        self.check_mem(aligned, n, m)?;
1048        self.pop_check(ValType::I32)?;
1049        self.push(t.into());
1050        Ok(())
1051    }
1052
1053    fn store(&mut self, aligned: bool, t: NumType, n: usize, m: MemArg) -> CheckResult {
1054        self.check_mem(aligned, n, m)?;
1055        self.pop_check(t.into())?;
1056        self.pop_check(ValType::I32)?;
1057        Ok(())
1058    }
1059
1060    fn testop(&mut self, t: NumType) -> CheckResult {
1061        self.pop_check(t.into())?;
1062        self.push(OpdType::I32);
1063        Ok(())
1064    }
1065
1066    fn relop(&mut self, t: NumType) -> CheckResult {
1067        self.pops([t.into(); 2][..].into())?;
1068        self.push(OpdType::I32);
1069        Ok(())
1070    }
1071
1072    fn unop(&mut self, t: NumType) -> CheckResult {
1073        self.swap(ValType::from(t))
1074    }
1075
1076    fn binop(&mut self, t: NumType) -> CheckResult {
1077        self.pop_check(t.into())?;
1078        self.swap(ValType::from(t))
1079    }
1080
1081    fn cvtop(&mut self, dst: NumType, src: NumType) -> CheckResult {
1082        self.pop_check(src.into())?;
1083        self.push(dst.into());
1084        Ok(())
1085    }
1086
1087    fn check_mem(&self, aligned: bool, n: usize, m: MemArg) -> CheckResult {
1088        check(!self.context.mems.is_empty())?;
1089        match (aligned, 1usize.checked_shl(m.align), n / 8) {
1090            (false, Some(m), n) if m <= n => Ok(()),
1091            (true, Some(m), n) if m == n => Ok(()),
1092            _ => Err(invalid()),
1093        }
1094    }
1095}
1096
1097fn delta(
1098    source: SideTableBranch, target: SideTableBranch, field: fn(SideTableBranch) -> isize,
1099) -> MResult<i32, Check> {
1100    let delta = field(target).checked_sub(field(source)).ok_or_else(side_table_unsupported)?;
1101    i32::try_from(delta).map_err(|_| side_table_unsupported())
1102}
1103
1104fn side_table_unsupported() -> Error {
1105    unsupported(if_debug!(Unsupported::SideTable))
1106}