1use 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
30pub 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
40pub 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 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 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 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 };
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 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 stack: usize,
576 values: usize,
578}
579
580#[derive(Debug, Default)]
581struct Label<'m, M: ValidMode> {
582 type_: FuncType<'m>,
583 kind: LabelKind,
585 polymorphic: bool,
587 stack: Vec<OpdType>,
588 branches: M::Branches,
589 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 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 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}