1use alloc::collections::btree_set::BTreeSet;
2use alloc::vec::Vec;
3use core::iter;
4
5use crate::core::indices::{
6 DataIdx, ElemIdx, FuncIdx, GlobalIdx, LabelIdx, LocalIdx, MemIdx, TableIdx, TypeIdx,
7};
8use crate::core::reader::section_header::{SectionHeader, SectionTy};
9use crate::core::reader::span::Span;
10use crate::core::reader::types::element::ElemType;
11use crate::core::reader::types::global::Global;
12use crate::core::reader::types::memarg::MemArg;
13use crate::core::reader::types::{BlockType, FuncType, MemType, NumType, TableType, ValType};
14use crate::core::reader::{WasmReadable, WasmReader};
15use crate::core::sidetable::{Sidetable, SidetableEntry};
16use crate::validation_stack::{LabelInfo, ValidationStack};
17use crate::{Error, RefType, Result};
18
19#[allow(clippy::too_many_arguments)]
20pub fn validate_code_section(
21 wasm: &mut WasmReader,
22 section_header: SectionHeader,
23 fn_types: &[FuncType],
24 type_idx_of_fn: &[usize],
25 num_imported_funcs: usize,
26 globals: &[Global],
27 memories: &[MemType],
28 data_count: &Option<u32>,
29 tables: &[TableType],
30 elements: &[ElemType],
31 validation_context_refs: &BTreeSet<FuncIdx>,
32 sidetable: &mut Sidetable,
33) -> Result<Vec<(Span, usize)>> {
34 assert_eq!(section_header.ty, SectionTy::Code);
35 let code_block_spans_stps = wasm.read_vec_enumerated(|wasm, idx| {
36 let ty_idx = type_idx_of_fn[idx + num_imported_funcs];
40 let func_ty = fn_types[ty_idx].clone();
41
42 let func_size = wasm.read_var_u32()?;
43 let func_block = wasm.make_span(func_size as usize)?;
44 let previous_pc = wasm.pc;
45
46 let locals = {
47 let params = func_ty.params.valtypes.iter().cloned();
48 let declared_locals = read_declared_locals(wasm)?;
49 params.chain(declared_locals).collect::<Vec<ValType>>()
50 };
51
52 let mut stack = ValidationStack::new_for_func(func_ty);
53 let stp = sidetable.len();
54
55 read_instructions(
56 wasm,
57 &mut stack,
58 sidetable,
59 &locals,
60 globals,
61 fn_types,
62 type_idx_of_fn,
63 memories,
64 data_count,
65 tables,
66 elements,
67 validation_context_refs,
68 )?;
69
70 if previous_pc + func_size as usize != wasm.pc {
72 todo!(
73 "throw error because there are trailing unreachable instructions in the code block"
74 )
75 }
76
77 Ok((func_block, stp))
78 })?;
79
80 trace!(
81 "Read code section. Found {} code blocks",
82 code_block_spans_stps.len()
83 );
84
85 Ok(code_block_spans_stps)
86}
87
88pub fn read_declared_locals(wasm: &mut WasmReader) -> Result<Vec<ValType>> {
89 let locals = wasm.read_vec(|wasm| {
90 let n = wasm.read_var_u32()? as usize;
91 let valtype = ValType::read(wasm)?;
92
93 Ok((n, valtype))
94 })?;
95
96 let mut total_no_of_locals: usize = 0;
101 for local in &locals {
102 let temp = local.0;
103 if temp > i32::MAX as usize {
104 return Err(Error::TooManyLocals(total_no_of_locals));
105 };
106 total_no_of_locals = match total_no_of_locals.checked_add(temp) {
107 None => return Err(Error::TooManyLocals(total_no_of_locals)),
108 Some(n) => n,
109 }
110 }
111
112 if total_no_of_locals > i32::MAX as usize {
113 return Err(Error::TooManyLocals(total_no_of_locals));
114 }
115
116 let locals = locals
118 .into_iter()
119 .flat_map(|entry| iter::repeat(entry.1).take(entry.0))
120 .collect::<Vec<ValType>>();
121
122 Ok(locals)
123}
124
125fn generate_unbackpatched_sidetable_entry(
132 wasm: &WasmReader,
133 sidetable: &mut Sidetable,
134 valcnt: usize,
135 popcnt: usize,
136 label_info: &mut LabelInfo,
137) {
138 let stp_here = sidetable.len();
139
140 sidetable.push(SidetableEntry {
141 delta_pc: wasm.pc as isize,
142 delta_stp: stp_here as isize,
143 popcnt,
144 valcnt,
145 });
146
147 match label_info {
148 LabelInfo::Block { stps_to_backpatch } => stps_to_backpatch.push(stp_here),
149 LabelInfo::Loop { ip, stp } => {
150 sidetable[stp_here].delta_pc = *ip as isize - wasm.pc as isize;
152 sidetable[stp_here].delta_stp = *stp as isize - stp_here as isize;
153 }
154 LabelInfo::If {
155 stps_to_backpatch, ..
156 } => stps_to_backpatch.push(stp_here),
157 LabelInfo::Func { stps_to_backpatch } => stps_to_backpatch.push(stp_here),
158 LabelInfo::Untyped => {
159 unreachable!("this label is for untyped wasm sequences")
160 }
161 }
162}
163
164fn validate_intrablock_jump_and_generate_sidetable_entry(
166 wasm: &WasmReader,
167 label_idx: usize,
168 stack: &mut ValidationStack,
169 sidetable: &mut Sidetable,
170 unify_to_expected_types: bool,
171) -> Result<()> {
172 let ctrl_stack_len = stack.ctrl_stack.len();
173
174 stack.assert_val_types_of_label_jump_types_on_top(label_idx, unify_to_expected_types)?;
175
176 let targeted_ctrl_block_entry = stack
177 .ctrl_stack
178 .get(ctrl_stack_len - label_idx - 1)
179 .ok_or(Error::InvalidLabelIdx(label_idx))?;
180
181 let valcnt = targeted_ctrl_block_entry.label_types().len();
182 let popcnt = stack.len() - targeted_ctrl_block_entry.height - valcnt;
183
184 let label_info = &mut stack
185 .ctrl_stack
186 .get_mut(ctrl_stack_len - label_idx - 1)
187 .unwrap()
188 .label_info;
189
190 generate_unbackpatched_sidetable_entry(wasm, sidetable, valcnt, popcnt, label_info);
191 Ok(())
192}
193
194#[allow(clippy::too_many_arguments)]
195fn read_instructions(
196 wasm: &mut WasmReader,
197 stack: &mut ValidationStack,
198 sidetable: &mut Sidetable,
199 locals: &[ValType],
200 globals: &[Global],
201 fn_types: &[FuncType],
202 type_idx_of_fn: &[usize],
203 memories: &[MemType],
204 data_count: &Option<u32>,
205 tables: &[TableType],
206 elements: &[ElemType],
207 validation_context_refs: &BTreeSet<FuncIdx>,
208) -> Result<()> {
209 loop {
210 let Ok(first_instr_byte) = wasm.read_u8() else {
211 return Err(Error::ExprMissingEnd);
213 };
214
215 #[cfg(debug_assertions)]
216 crate::core::utils::print_beautiful_instruction_name_1_byte(first_instr_byte, wasm.pc);
217
218 #[cfg(not(debug_assertions))]
219 trace!("Read instruction byte {first_instr_byte:#04X?} ({first_instr_byte}) at wasm_binary[{}]", wasm.pc);
220
221 use crate::core::reader::types::opcode::*;
222 match first_instr_byte {
223 NOP => {}
225 BLOCK => {
227 let block_ty = BlockType::read(wasm)?.as_func_type(fn_types)?;
228 let label_info = LabelInfo::Block {
229 stps_to_backpatch: Vec::new(),
230 };
231 stack.assert_push_ctrl(label_info, block_ty, true)?;
235 }
236 LOOP => {
237 let block_ty = BlockType::read(wasm)?.as_func_type(fn_types)?;
238 let label_info = LabelInfo::Loop {
239 ip: wasm.pc,
240 stp: sidetable.len(),
241 };
242 stack.assert_push_ctrl(label_info, block_ty, true)?;
246 }
247 IF => {
248 let block_ty = BlockType::read(wasm)?.as_func_type(fn_types)?;
249
250 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
251
252 let stp_here = sidetable.len();
253 sidetable.push(SidetableEntry {
254 delta_pc: wasm.pc as isize,
255 delta_stp: stp_here as isize,
256 popcnt: 0,
257 valcnt: block_ty.params.valtypes.len(),
258 });
259
260 let label_info = LabelInfo::If {
261 stp: stp_here,
262 stps_to_backpatch: Vec::new(),
263 };
264 stack.assert_push_ctrl(label_info, block_ty, true)?;
268 }
269 ELSE => {
270 let (mut label_info, block_ty) = stack.assert_pop_ctrl(true)?;
271 if let LabelInfo::If {
272 stp,
273 stps_to_backpatch,
274 } = &mut label_info
275 {
276 if *stp == usize::MAX {
277 return Err(Error::ElseWithoutMatchingIf);
279 }
280 let stp_here = sidetable.len();
281 sidetable.push(SidetableEntry {
282 delta_pc: wasm.pc as isize,
283 delta_stp: stp_here as isize,
284 popcnt: 0,
285 valcnt: block_ty.returns.valtypes.len(),
286 });
287 stps_to_backpatch.push(stp_here);
288
289 sidetable[*stp].delta_pc = wasm.pc as isize - sidetable[*stp].delta_pc;
290 sidetable[*stp].delta_stp =
291 sidetable.len() as isize - sidetable[*stp].delta_stp;
292
293 *stp = usize::MAX; for valtype in block_ty.returns.valtypes.iter().rev() {
296 stack.assert_pop_val_type(*valtype)?;
297 }
298
299 for valtype in block_ty.params.valtypes.iter() {
300 stack.push_valtype(*valtype);
301 }
302 stack.assert_push_ctrl(label_info, block_ty, true)?;
306 } else {
307 return Err(Error::ElseWithoutMatchingIf);
308 }
309 }
310 BR => {
311 let label_idx = wasm.read_var_u32()? as LabelIdx;
312 validate_intrablock_jump_and_generate_sidetable_entry(
313 wasm, label_idx, stack, sidetable, false,
314 )?;
315 stack.make_unspecified()?;
316 }
317 BR_IF => {
318 let label_idx = wasm.read_var_u32()? as LabelIdx;
319 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
320 validate_intrablock_jump_and_generate_sidetable_entry(
324 wasm, label_idx, stack, sidetable, true,
325 )?;
326 }
327 BR_TABLE => {
328 let label_vec = wasm.read_vec(|wasm| wasm.read_var_u32().map(|v| v as LabelIdx))?;
329 let max_label_idx = wasm.read_var_u32()? as LabelIdx;
330 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
331 for label_idx in &label_vec {
332 validate_intrablock_jump_and_generate_sidetable_entry(
333 wasm, *label_idx, stack, sidetable, false,
334 )?;
335 }
336
337 validate_intrablock_jump_and_generate_sidetable_entry(
338 wasm,
339 max_label_idx,
340 stack,
341 sidetable,
342 false,
343 )?;
344
345 let max_label_arity = stack
352 .ctrl_stack
353 .get(stack.ctrl_stack.len() - max_label_idx - 1)
354 .unwrap()
355 .label_types()
356 .len();
357 for label_idx in &label_vec {
358 let label_arity = stack
359 .ctrl_stack
360 .get(stack.ctrl_stack.len() - *label_idx - 1)
361 .unwrap()
362 .label_types()
363 .len();
364 if max_label_arity != label_arity {
365 return Err(Error::InvalidLabelIdx(*label_idx));
366 }
367 }
368
369 stack.make_unspecified()?;
370 }
371 END => {
372 let (label_info, block_ty) = stack.assert_pop_ctrl(true)?;
376 let stp_here = sidetable.len();
377
378 match label_info {
379 LabelInfo::Block { stps_to_backpatch } => {
380 stps_to_backpatch.iter().for_each(|i| {
381 sidetable[*i].delta_pc = (wasm.pc as isize) - sidetable[*i].delta_pc;
382 sidetable[*i].delta_stp = (stp_here as isize) - sidetable[*i].delta_stp;
383 });
384 }
385 LabelInfo::If {
386 stp,
387 stps_to_backpatch,
388 } => {
389 if stp != usize::MAX {
390 if !(block_ty.params == block_ty.returns) {
395 return Err(Error::IfWithoutMatchingElse);
396 }
397
398 sidetable[stp].delta_pc = (wasm.pc as isize) - sidetable[stp].delta_pc;
401 sidetable[stp].delta_stp =
402 (stp_here as isize) - sidetable[stp].delta_stp;
403 }
404 stps_to_backpatch.iter().for_each(|i| {
405 sidetable[*i].delta_pc = (wasm.pc as isize) - sidetable[*i].delta_pc;
406 sidetable[*i].delta_stp = (stp_here as isize) - sidetable[*i].delta_stp;
407 });
408 }
409 LabelInfo::Loop { .. } => (),
410 LabelInfo::Func { stps_to_backpatch } => {
411 stps_to_backpatch.iter().for_each(|i| {
414 sidetable[*i].delta_pc =
415 (wasm.pc as isize) - sidetable[*i].delta_pc - 1; sidetable[*i].delta_stp = (stp_here as isize) - sidetable[*i].delta_stp;
417 });
418 }
419 LabelInfo::Untyped => unreachable!("this label is for untyped wasm sequences"),
420 }
421
422 if stack.ctrl_stack.is_empty() {
423 return Ok(());
424 }
425 }
426 RETURN => {
427 let label_idx = stack.ctrl_stack.len() - 1; validate_intrablock_jump_and_generate_sidetable_entry(
429 wasm, label_idx, stack, sidetable, false,
430 )?;
431 stack.make_unspecified()?;
432 }
433 CALL => {
435 let func_to_call_idx = wasm.read_var_u32()? as FuncIdx;
436 let func_ty = &fn_types[type_idx_of_fn[func_to_call_idx]];
437
438 for typ in func_ty.params.valtypes.iter().rev() {
439 stack.assert_pop_val_type(*typ)?;
440 }
441
442 for typ in func_ty.returns.valtypes.iter() {
443 stack.push_valtype(*typ);
444 }
445 }
446 CALL_INDIRECT => {
447 let type_idx = wasm.read_var_u32()? as TypeIdx;
448
449 let table_idx = wasm.read_var_u32()? as TableIdx;
450
451 if tables.len() <= table_idx {
452 return Err(Error::TableIsNotDefined(table_idx));
453 }
454
455 let tab = &tables[table_idx];
456
457 if tab.et != RefType::FuncRef {
458 return Err(Error::WrongRefTypeForInteropValue(tab.et, RefType::FuncRef));
459 }
460
461 if type_idx >= fn_types.len() {
462 return Err(Error::FunctionTypeIsNotDefined(type_idx));
463 }
464
465 let func_ty = &fn_types[type_idx];
466
467 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
468
469 for typ in func_ty.params.valtypes.iter().rev() {
470 stack.assert_pop_val_type(*typ)?;
471 }
472
473 for typ in func_ty.returns.valtypes.iter() {
474 stack.push_valtype(*typ);
475 }
476 }
477 UNREACHABLE => {
479 stack.make_unspecified()?;
480 }
481 DROP => {
482 stack.drop_val()?;
483 }
484 SELECT => {
485 stack.validate_polymorphic_select()?;
486 }
487 SELECT_T => {
488 let type_vec = wasm.read_vec(ValType::read)?;
489 if type_vec.len() != 1 {
490 return Err(Error::InvalidSelectTypeVector);
491 }
492 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
493 stack.assert_pop_val_type(type_vec[0])?;
494 stack.assert_pop_val_type(type_vec[0])?;
495 stack.push_valtype(type_vec[0]);
496 }
497 LOCAL_GET => {
499 let local_idx = wasm.read_var_u32()? as LocalIdx;
500 let local_ty = locals.get(local_idx).ok_or(Error::InvalidLocalIdx)?;
501 stack.push_valtype(*local_ty);
502 }
503 LOCAL_SET => {
505 let local_idx = wasm.read_var_u32()? as LocalIdx;
506 let local_ty = locals.get(local_idx).ok_or(Error::InvalidLocalIdx)?;
507 stack.assert_pop_val_type(*local_ty)?;
508 }
509 LOCAL_TEE => {
511 let local_idx = wasm.read_var_u32()? as LocalIdx;
512 let local_ty = locals.get(local_idx).ok_or(Error::InvalidLocalIdx)?;
513 stack.assert_val_types_on_top(&[*local_ty], true)?;
514 }
515 GLOBAL_GET => {
517 let global_idx = wasm.read_var_u32()? as GlobalIdx;
518 let global = globals
519 .get(global_idx)
520 .ok_or(Error::InvalidGlobalIdx(global_idx))?;
521
522 stack.push_valtype(global.ty.ty);
523 trace!(
524 "Instruction: global.get '{}' [] -> [{:?}]",
525 global_idx,
526 global.ty.ty
528 );
529 }
530 GLOBAL_SET => {
532 let global_idx = wasm.read_var_u32()? as GlobalIdx;
533 let global = globals
534 .get(global_idx)
535 .ok_or(Error::InvalidGlobalIdx(global_idx))?;
536
537 if !global.ty.is_mut {
538 return Err(Error::GlobalIsConst);
539 }
540
541 stack.assert_pop_val_type(global.ty.ty)?;
542 }
543 TABLE_GET => {
544 let table_idx = wasm.read_var_u32()? as TableIdx;
545
546 if tables.len() <= table_idx {
547 return Err(Error::TableIsNotDefined(table_idx));
548 }
549
550 let t = tables.get(table_idx).unwrap().et;
551
552 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
553 stack.push_valtype(ValType::RefType(t));
554 }
555 TABLE_SET => {
556 let table_idx = wasm.read_var_u32()? as TableIdx;
557
558 if tables.len() <= table_idx {
559 return Err(Error::TableIsNotDefined(table_idx));
560 }
561
562 let t = tables.get(table_idx).unwrap().et;
563
564 stack.assert_pop_ref_type(Some(t))?;
565 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
566 }
567 I32_LOAD => {
568 if memories.is_empty() {
569 return Err(Error::MemoryIsNotDefined(0));
570 }
571 let memarg = MemArg::read(wasm)?;
572 if memarg.align > 4 {
573 return Err(Error::ErroneousAlignment(memarg.align, 4));
574 }
575 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
576 stack.push_valtype(ValType::NumType(NumType::I32));
577 }
578 I64_LOAD => {
579 if memories.is_empty() {
580 return Err(Error::MemoryIsNotDefined(0));
581 }
582 let memarg = MemArg::read(wasm)?;
583 if memarg.align > 8 {
584 return Err(Error::ErroneousAlignment(memarg.align, 8));
585 }
586 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
587 stack.push_valtype(ValType::NumType(NumType::I64));
588 }
589 F32_LOAD => {
590 if memories.is_empty() {
591 return Err(Error::MemoryIsNotDefined(0));
592 }
593 let memarg = MemArg::read(wasm)?;
594 if memarg.align > 4 {
595 return Err(Error::ErroneousAlignment(memarg.align, 4));
596 }
597 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
598 stack.push_valtype(ValType::NumType(NumType::F32));
599 }
600 F64_LOAD => {
601 if memories.is_empty() {
602 return Err(Error::MemoryIsNotDefined(0));
603 }
604 let memarg = MemArg::read(wasm)?;
605 if memarg.align > 8 {
606 return Err(Error::ErroneousAlignment(memarg.align, 8));
607 }
608 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
609 stack.push_valtype(ValType::NumType(NumType::F64));
610 }
611 I32_LOAD8_S => {
612 if memories.is_empty() {
613 return Err(Error::MemoryIsNotDefined(0));
614 }
615 let memarg = MemArg::read(wasm)?;
616 if memarg.align > 1 {
617 return Err(Error::ErroneousAlignment(memarg.align, 1));
618 }
619 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
620 stack.push_valtype(ValType::NumType(NumType::I32));
621 }
622 I32_LOAD8_U => {
623 if memories.is_empty() {
624 return Err(Error::MemoryIsNotDefined(0));
625 }
626 let memarg = MemArg::read(wasm)?;
627 if memarg.align > 1 {
628 return Err(Error::ErroneousAlignment(memarg.align, 1));
629 }
630 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
631 stack.push_valtype(ValType::NumType(NumType::I32));
632 }
633 I32_LOAD16_S => {
634 if memories.is_empty() {
635 return Err(Error::MemoryIsNotDefined(0));
636 }
637 let memarg = MemArg::read(wasm)?;
638 if memarg.align > 2 {
639 return Err(Error::ErroneousAlignment(memarg.align, 2));
640 }
641 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
642 stack.push_valtype(ValType::NumType(NumType::I32));
643 }
644 I32_LOAD16_U => {
645 if memories.is_empty() {
646 return Err(Error::MemoryIsNotDefined(0));
647 }
648 let memarg = MemArg::read(wasm)?;
649 if memarg.align > 2 {
650 return Err(Error::ErroneousAlignment(memarg.align, 2));
651 }
652 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
653 stack.push_valtype(ValType::NumType(NumType::I32));
654 }
655 I64_LOAD8_S => {
656 if memories.is_empty() {
657 return Err(Error::MemoryIsNotDefined(0));
658 }
659 let memarg = MemArg::read(wasm)?;
660 if memarg.align > 1 {
661 return Err(Error::ErroneousAlignment(memarg.align, 1));
662 }
663 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
664 stack.push_valtype(ValType::NumType(NumType::I64));
665 }
666 I64_LOAD8_U => {
667 if memories.is_empty() {
668 return Err(Error::MemoryIsNotDefined(0));
669 }
670 let memarg = MemArg::read(wasm)?;
671 if memarg.align > 1 {
672 return Err(Error::ErroneousAlignment(memarg.align, 1));
673 }
674 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
675 stack.push_valtype(ValType::NumType(NumType::I64));
676 }
677 I64_LOAD16_S => {
678 if memories.is_empty() {
679 return Err(Error::MemoryIsNotDefined(0));
680 }
681 let memarg = MemArg::read(wasm)?;
682 if memarg.align > 2 {
683 return Err(Error::ErroneousAlignment(memarg.align, 2));
684 }
685 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
686 stack.push_valtype(ValType::NumType(NumType::I64));
687 }
688 I64_LOAD16_U => {
689 if memories.is_empty() {
690 return Err(Error::MemoryIsNotDefined(0));
691 }
692 let memarg = MemArg::read(wasm)?;
693 if memarg.align > 2 {
694 return Err(Error::ErroneousAlignment(memarg.align, 2));
695 }
696 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
697 stack.push_valtype(ValType::NumType(NumType::I64));
698 }
699 I64_LOAD32_S => {
700 if memories.is_empty() {
701 return Err(Error::MemoryIsNotDefined(0));
702 }
703 let memarg = MemArg::read(wasm)?;
704 if memarg.align > 4 {
705 return Err(Error::ErroneousAlignment(memarg.align, 4));
706 }
707 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
708 stack.push_valtype(ValType::NumType(NumType::I64));
709 }
710 I64_LOAD32_U => {
711 if memories.is_empty() {
712 return Err(Error::MemoryIsNotDefined(0));
713 }
714 let memarg = MemArg::read(wasm)?;
715 if memarg.align > 4 {
716 return Err(Error::ErroneousAlignment(memarg.align, 4));
717 }
718 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
719 stack.push_valtype(ValType::NumType(NumType::I64));
720 }
721 I32_STORE => {
722 if memories.is_empty() {
723 return Err(Error::MemoryIsNotDefined(0));
724 }
725 let memarg = MemArg::read(wasm)?;
726 if memarg.align > 4 {
727 return Err(Error::ErroneousAlignment(memarg.align, 4));
728 }
729 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
730 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
731 }
732 I64_STORE => {
733 if memories.is_empty() {
734 return Err(Error::MemoryIsNotDefined(0));
735 }
736 let memarg = MemArg::read(wasm)?;
737 if memarg.align > 8 {
738 return Err(Error::ErroneousAlignment(memarg.align, 8));
739 }
740 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
741 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
742 }
743 F32_STORE => {
744 if memories.is_empty() {
745 return Err(Error::MemoryIsNotDefined(0));
746 }
747 let memarg = MemArg::read(wasm)?;
748 if memarg.align > 4 {
749 return Err(Error::ErroneousAlignment(memarg.align, 4));
750 }
751 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
752 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
753 }
754 F64_STORE => {
755 if memories.is_empty() {
756 return Err(Error::MemoryIsNotDefined(0));
757 }
758 let memarg = MemArg::read(wasm)?;
759 if memarg.align > 8 {
760 return Err(Error::ErroneousAlignment(memarg.align, 8));
761 }
762 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
763 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
764 }
765 I32_STORE8 => {
766 if memories.is_empty() {
767 return Err(Error::MemoryIsNotDefined(0));
768 }
769 let memarg = MemArg::read(wasm)?;
770 if memarg.align > 1 {
771 return Err(Error::ErroneousAlignment(memarg.align, 1));
772 }
773 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
774 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
775 }
776 I32_STORE16 => {
777 if memories.is_empty() {
778 return Err(Error::MemoryIsNotDefined(0));
779 }
780 let memarg = MemArg::read(wasm)?;
781 if memarg.align > 2 {
782 return Err(Error::ErroneousAlignment(memarg.align, 2));
783 }
784 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
785 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
786 }
787 I64_STORE8 => {
788 if memories.is_empty() {
789 return Err(Error::MemoryIsNotDefined(0));
790 }
791 let memarg = MemArg::read(wasm)?;
792 if memarg.align > 1 {
793 return Err(Error::ErroneousAlignment(memarg.align, 1));
794 }
795 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
796 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
797 }
798 I64_STORE16 => {
799 if memories.is_empty() {
800 return Err(Error::MemoryIsNotDefined(0));
801 }
802 let memarg = MemArg::read(wasm)?;
803 if memarg.align > 2 {
804 return Err(Error::ErroneousAlignment(memarg.align, 2));
805 }
806 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
807 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
808 }
809 I64_STORE32 => {
810 if memories.is_empty() {
811 return Err(Error::MemoryIsNotDefined(0));
812 }
813 let memarg = MemArg::read(wasm)?;
814 if memarg.align > 4 {
815 return Err(Error::ErroneousAlignment(memarg.align, 4));
816 }
817 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
818 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
819 }
820 MEMORY_SIZE => {
821 let mem_idx = wasm.read_u8()? as MemIdx;
822 if mem_idx != 0 {
823 return Err(Error::UnsupportedProposal(
824 crate::core::error::Proposal::MultipleMemories,
825 ));
826 }
827 if memories.len() <= mem_idx {
828 return Err(Error::MemoryIsNotDefined(mem_idx));
829 }
830 stack.push_valtype(ValType::NumType(NumType::I32));
831 }
832 MEMORY_GROW => {
833 let mem_idx = wasm.read_u8()? as MemIdx;
834 if mem_idx != 0 {
835 return Err(Error::UnsupportedProposal(
836 crate::core::error::Proposal::MultipleMemories,
837 ));
838 }
839 if memories.len() <= mem_idx {
840 return Err(Error::MemoryIsNotDefined(mem_idx));
841 }
842 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
843 stack.push_valtype(ValType::NumType(NumType::I32));
844 }
845 I32_CONST => {
847 let _num = wasm.read_var_i32()?;
848 stack.push_valtype(ValType::NumType(NumType::I32));
849 }
850 I64_CONST => {
851 let _num = wasm.read_var_i64()?;
852 stack.push_valtype(ValType::NumType(NumType::I64));
853 }
854 F32_CONST => {
855 let _num = wasm.read_var_f32()?;
856 stack.push_valtype(ValType::NumType(NumType::F32));
857 }
858 F64_CONST => {
859 let _num = wasm.read_var_f64()?;
860 stack.push_valtype(ValType::NumType(NumType::F64));
861 }
862 I32_EQZ => {
863 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
864
865 stack.push_valtype(ValType::NumType(NumType::I32));
866 }
867 I32_EQ | I32_NE | I32_LT_S | I32_LT_U | I32_GT_S | I32_GT_U | I32_LE_S | I32_LE_U
868 | I32_GE_S | I32_GE_U => {
869 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
870 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
871
872 stack.push_valtype(ValType::NumType(NumType::I32));
873 }
874 I64_EQZ => {
875 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
876
877 stack.push_valtype(ValType::NumType(NumType::I32));
878 }
879 I64_EQ | I64_NE | I64_LT_S | I64_LT_U | I64_GT_S | I64_GT_U | I64_LE_S | I64_LE_U
880 | I64_GE_S | I64_GE_U => {
881 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
882 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
883
884 stack.push_valtype(ValType::NumType(NumType::I32));
885 }
886 F32_EQ | F32_NE | F32_LT | F32_GT | F32_LE | F32_GE => {
887 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
888 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
889
890 stack.push_valtype(ValType::NumType(NumType::I32));
891 }
892 F64_EQ | F64_NE | F64_LT | F64_GT | F64_LE | F64_GE => {
893 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
894 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
895
896 stack.push_valtype(ValType::NumType(NumType::I32));
897 }
898 F32_ABS | F32_NEG | F32_CEIL | F32_FLOOR | F32_TRUNC | F32_NEAREST | F32_SQRT => {
899 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
900
901 stack.push_valtype(ValType::NumType(NumType::F32));
902 }
903 F32_ADD | F32_SUB | F32_MUL | F32_DIV | F32_MIN | F32_MAX | F32_COPYSIGN => {
904 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
905 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
906
907 stack.push_valtype(ValType::NumType(NumType::F32));
908 }
909 F64_ABS | F64_NEG | F64_CEIL | F64_FLOOR | F64_TRUNC | F64_NEAREST | F64_SQRT => {
910 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
911
912 stack.push_valtype(ValType::NumType(NumType::F64));
913 }
914 F64_ADD | F64_SUB | F64_MUL | F64_DIV | F64_MIN | F64_MAX | F64_COPYSIGN => {
915 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
916 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
917
918 stack.push_valtype(ValType::NumType(NumType::F64));
919 }
920 I32_ADD | I32_SUB | I32_MUL | I32_DIV_S | I32_DIV_U | I32_REM_S => {
921 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
922 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
923
924 stack.push_valtype(ValType::NumType(NumType::I32));
925 }
926 I32_CLZ | I32_CTZ | I32_POPCNT => {
928 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
929
930 stack.push_valtype(ValType::NumType(NumType::I32));
931 }
932 I32_REM_U | I32_AND | I32_OR | I32_XOR | I32_SHL | I32_SHR_S | I32_SHR_U | I32_ROTL
933 | I32_ROTR => {
934 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
935 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
936
937 stack.push_valtype(ValType::NumType(NumType::I32));
938 }
939 I64_CLZ | I64_CTZ | I64_POPCNT => {
940 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
941
942 stack.push_valtype(ValType::NumType(NumType::I64));
943 }
944
945 I64_ADD | I64_SUB | I64_MUL | I64_DIV_S | I64_DIV_U | I64_REM_S | I64_REM_U
946 | I64_AND | I64_OR | I64_XOR | I64_SHL | I64_SHR_S | I64_SHR_U | I64_ROTL
947 | I64_ROTR => {
948 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
949 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
950
951 stack.push_valtype(ValType::NumType(NumType::I64));
952 }
953
954 I32_WRAP_I64 => {
955 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
956
957 stack.push_valtype(ValType::NumType(NumType::I32));
958 }
959
960 I32_TRUNC_F32_S | I32_TRUNC_F32_U | I32_REINTERPRET_F32 => {
961 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
962
963 stack.push_valtype(ValType::NumType(NumType::I32));
964 }
965
966 I32_TRUNC_F64_S | I32_TRUNC_F64_U => {
967 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
968
969 stack.push_valtype(ValType::NumType(NumType::I32));
970 }
971
972 I64_EXTEND_I32_S | I64_EXTEND_I32_U => {
973 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
974
975 stack.push_valtype(ValType::NumType(NumType::I64));
976 }
977
978 I64_TRUNC_F32_S | I64_TRUNC_F32_U => {
979 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
980
981 stack.push_valtype(ValType::NumType(NumType::I64));
982 }
983
984 I64_TRUNC_F64_S | I64_TRUNC_F64_U | I64_REINTERPRET_F64 => {
985 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
986
987 stack.push_valtype(ValType::NumType(NumType::I64));
988 }
989
990 F32_CONVERT_I32_S | F32_CONVERT_I32_U | F32_REINTERPRET_I32 => {
991 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
992
993 stack.push_valtype(ValType::NumType(NumType::F32));
994 }
995
996 F32_CONVERT_I64_S | F32_CONVERT_I64_U => {
997 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
998
999 stack.push_valtype(ValType::NumType(NumType::F32));
1000 }
1001
1002 F32_DEMOTE_F64 => {
1003 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1004
1005 stack.push_valtype(ValType::NumType(NumType::F32));
1006 }
1007
1008 F64_CONVERT_I32_S | F64_CONVERT_I32_U => {
1009 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1010
1011 stack.push_valtype(ValType::NumType(NumType::F64));
1012 }
1013
1014 F64_CONVERT_I64_S | F64_CONVERT_I64_U | F64_REINTERPRET_I64 => {
1015 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1016
1017 stack.push_valtype(ValType::NumType(NumType::F64));
1018 }
1019
1020 F64_PROMOTE_F32 => {
1021 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1022
1023 stack.push_valtype(ValType::NumType(NumType::F64));
1024 }
1025
1026 REF_NULL => {
1027 let reftype = RefType::read(wasm)?;
1028 stack.push_valtype(ValType::RefType(reftype));
1030 }
1031
1032 REF_IS_NULL => {
1033 stack.assert_pop_ref_type(None)?;
1034 stack.push_valtype(ValType::NumType(NumType::I32));
1035 }
1036
1037 REF_FUNC => {
1038 let func_idx = wasm.read_var_u32()? as FuncIdx;
1039
1040 if type_idx_of_fn.len() <= func_idx {
1042 return Err(Error::FunctionIsNotDefined(func_idx));
1043 }
1044
1045 if !validation_context_refs.contains(&func_idx) {
1048 return Err(Error::ReferencingAnUnreferencedFunction(func_idx));
1049 }
1050
1051 stack.push_valtype(ValType::RefType(RefType::FuncRef));
1052 }
1053
1054 FC_EXTENSIONS => {
1055 let Ok(second_instr) = wasm.read_var_u32() else {
1056 return Err(Error::ExprMissingEnd);
1058 };
1059
1060 #[cfg(debug_assertions)]
1061 crate::core::utils::print_beautiful_fc_extension(second_instr, wasm.pc);
1062
1063 #[cfg(not(debug_assertions))]
1064 trace!(
1065 "Read instruction byte {second_instr} at wasm_binary[{}]",
1066 wasm.pc
1067 );
1068
1069 use crate::core::reader::types::opcode::fc_extensions::*;
1070 match second_instr {
1071 I32_TRUNC_SAT_F32_S => {
1072 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1073 stack.push_valtype(ValType::NumType(NumType::I32));
1074 }
1075 I32_TRUNC_SAT_F32_U => {
1076 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1077 stack.push_valtype(ValType::NumType(NumType::I32));
1078 }
1079 I32_TRUNC_SAT_F64_S => {
1080 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1081 stack.push_valtype(ValType::NumType(NumType::I32));
1082 }
1083 I32_TRUNC_SAT_F64_U => {
1084 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1085 stack.push_valtype(ValType::NumType(NumType::I32));
1086 }
1087 I64_TRUNC_SAT_F32_S => {
1088 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1089 stack.push_valtype(ValType::NumType(NumType::I64));
1090 }
1091 I64_TRUNC_SAT_F32_U => {
1092 stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1093 stack.push_valtype(ValType::NumType(NumType::I64));
1094 }
1095 I64_TRUNC_SAT_F64_S => {
1096 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1097 stack.push_valtype(ValType::NumType(NumType::I64));
1098 }
1099 I64_TRUNC_SAT_F64_U => {
1100 stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1101 stack.push_valtype(ValType::NumType(NumType::I64));
1102 }
1103 MEMORY_INIT => {
1104 let data_idx = wasm.read_var_u32()? as DataIdx;
1105 let mem_idx = wasm.read_u8()? as MemIdx;
1106 if mem_idx != 0 {
1107 return Err(Error::UnsupportedProposal(
1108 crate::core::error::Proposal::MultipleMemories,
1109 ));
1110 }
1111 if memories.len() <= mem_idx {
1112 return Err(Error::MemoryIsNotDefined(mem_idx));
1113 }
1114 if data_count.is_none() {
1115 return Err(Error::NoDataSegments);
1116 }
1117 if data_count.unwrap() as usize <= data_idx {
1118 return Err(Error::DataSegmentNotFound(data_idx));
1119 }
1120 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1121 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1122 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1123 }
1124 DATA_DROP => {
1125 if data_count.is_none() {
1126 return Err(Error::NoDataSegments);
1127 }
1128 let data_idx = wasm.read_var_u32()? as DataIdx;
1129 if data_count.unwrap() as usize <= data_idx {
1130 return Err(Error::DataSegmentNotFound(data_idx));
1131 }
1132 }
1133 MEMORY_COPY => {
1134 let (dst, src) = (wasm.read_u8()? as usize, wasm.read_u8()? as usize);
1135 if dst != 0 || src != 0 {
1136 return Err(Error::UnsupportedProposal(
1137 crate::core::error::Proposal::MultipleMemories,
1138 ));
1139 }
1140 if memories.is_empty() {
1141 return Err(Error::MemoryIsNotDefined(0));
1142 }
1143 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1144 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1145 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1146 }
1147 MEMORY_FILL => {
1148 let mem_idx = wasm.read_u8()? as MemIdx;
1149 if mem_idx != 0 {
1150 return Err(Error::UnsupportedProposal(
1151 crate::core::error::Proposal::MultipleMemories,
1152 ));
1153 }
1154 if memories.len() <= mem_idx {
1155 return Err(Error::MemoryIsNotDefined(mem_idx));
1156 }
1157 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1158 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1159 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1160 }
1161 TABLE_INIT => {
1162 let elem_idx = wasm.read_var_u32()? as ElemIdx;
1163 let table_idx = wasm.read_var_u32()? as TableIdx;
1164
1165 if tables.len() <= table_idx {
1166 return Err(Error::TableIsNotDefined(table_idx));
1167 }
1168
1169 let t1 = tables[table_idx].et;
1170
1171 if elements.len() <= elem_idx {
1172 return Err(Error::ElementIsNotDefined(elem_idx));
1173 }
1174
1175 let t2 = elements[elem_idx].to_ref_type();
1176
1177 if t1 != t2 {
1178 return Err(Error::DifferentRefTypes(t1, t2));
1179 }
1180 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1181 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1182 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1184 }
1185 ELEM_DROP => {
1186 let elem_idx = wasm.read_var_u32()? as ElemIdx;
1187
1188 if elements.len() <= elem_idx {
1189 return Err(Error::ElementIsNotDefined(elem_idx));
1190 }
1191 }
1192 TABLE_COPY => {
1193 let table_x_idx = wasm.read_var_u32()? as TableIdx;
1194 let table_y_idx = wasm.read_var_u32()? as TableIdx;
1195
1196 if tables.len() <= table_x_idx {
1197 return Err(Error::TableIsNotDefined(table_x_idx));
1198 }
1199
1200 if tables.len() <= table_y_idx {
1201 return Err(Error::TableIsNotDefined(table_y_idx));
1202 }
1203
1204 let t1 = tables[table_x_idx].et;
1205 let t2 = tables[table_y_idx].et;
1206
1207 if t1 != t2 {
1208 return Err(Error::DifferentRefTypes(t1, t2));
1209 }
1210
1211 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1212 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1213 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1214 }
1215 TABLE_GROW => {
1216 let table_idx = wasm.read_var_u32()? as TableIdx;
1217
1218 if tables.len() <= table_idx {
1219 return Err(Error::TableIsNotDefined(table_idx));
1220 }
1221
1222 let t = tables[table_idx].et;
1223
1224 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1225 stack.assert_pop_ref_type(Some(t))?;
1226
1227 stack.push_valtype(ValType::NumType(NumType::I32));
1228 }
1229 TABLE_SIZE => {
1230 let table_idx = wasm.read_var_u32()? as TableIdx;
1231
1232 if tables.len() <= table_idx {
1233 return Err(Error::TableIsNotDefined(table_idx));
1234 }
1235
1236 stack.push_valtype(ValType::NumType(NumType::I32));
1237 }
1238 TABLE_FILL => {
1239 let table_idx = wasm.read_var_u32()? as TableIdx;
1240
1241 if tables.len() <= table_idx {
1242 return Err(Error::TableIsNotDefined(table_idx));
1243 }
1244
1245 let t = tables[table_idx].et;
1246
1247 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1248 stack.assert_pop_ref_type(Some(t))?;
1249 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1250 }
1251 _ => return Err(Error::InvalidMultiByteInstr(first_instr_byte, second_instr)),
1252 }
1253 }
1254
1255 I32_EXTEND8_S => {
1256 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1257
1258 stack.push_valtype(ValType::NumType(NumType::I32));
1259 }
1260 I32_EXTEND16_S => {
1261 stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1262
1263 stack.push_valtype(ValType::NumType(NumType::I32));
1264 }
1265 I64_EXTEND8_S => {
1266 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1267
1268 stack.push_valtype(ValType::NumType(NumType::I64));
1269 }
1270 I64_EXTEND16_S => {
1271 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1272
1273 stack.push_valtype(ValType::NumType(NumType::I64));
1274 }
1275 I64_EXTEND32_S => {
1276 stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1277
1278 stack.push_valtype(ValType::NumType(NumType::I64));
1279 }
1280 _ => return Err(Error::InvalidInstr(first_instr_byte)),
1281 }
1282 }
1283}