735                                                                                                                {
  736 
  737         
  738         operand_stack_type_tracker op_stack{local_bytes_checker, _options};
  739         std::vector<pc_element_t> pc_stack{{
  740               op_stack.depth(),
  741               ft.return_count ? ft.return_type : 
static_cast<uint32_t>(types::pseudo),
 
  743               false,
  745 
  746         
  747         
  748         
  751            pc_element_t& branch_target = pc_stack[pc_stack.size() - 
label - 1];
 
  752            std::visit(
overloaded{ [&](
label_t target) { code_writer.fix_branch(address, target); },
 
  753                                   [&](std::vector<branch_t>& relocations) { relocations.push_back(address); } },
  754               branch_target.relocations);
  755         };
  756 
  757         
  758         
  759         
  760         
  763            pc_element_t& branch_target = pc_stack[pc_stack.size() - 
label - 1];
 
  764            uint32_t result = op_stack.depth() - branch_target.operand_depth;
 
  765            if(branch_target.label_result != types::pseudo) {
  766               
  767               
  768               
  769               
  770               
  771               result |= 0x80000000;
  772               op_stack.top(branch_target.label_result);
  773            }
  774            return result;
  775         };
  776 
  777         
  778         auto exit_scope = [&]() {
  779            
  780            SYS_VM_ASSERT(pc_stack.size(), wasm_parse_exception, 
"unexpected end instruction");
 
  781            
  782            SYS_VM_ASSERT(!pc_stack.back().is_if || pc_stack.back().expected_result == types::pseudo, wasm_parse_exception, 
"wrong type");
 
  783            auto end_pos = code_writer.emit_end();
  784            if(auto* relocations = std::get_if<std::vector<branch_t>>(&pc_stack.back().relocations)) {
  785               for(auto branch_op : *relocations) {
  786                  code_writer.fix_branch(branch_op, end_pos);
  787               }
  788            }
  789            op_stack.pop_scope(pc_stack.back().expected_result);
  790            pc_stack.pop_back();
  791         };
  792 
  793         auto check_in_bounds = [&]{
  794            SYS_VM_ASSERT(!detail::get_allow_code_after_function_end(_options) || !pc_stack.empty(),
 
  795                          wasm_parse_exception, "code after function end");
  796         };
  797 
  798         while (code.offset() < bounds) {
  799            SYS_VM_ASSERT(pc_stack.size() <= detail::get_max_nested_structures(_options), wasm_parse_exception,
 
  800                          "nested structures validation failure");
  801 
  802            imap.on_instr_start(code_writer.get_addr(), code.raw());
  803 
  804            switch (*code++) {
  805               case opcodes::unreachable: check_in_bounds(); code_writer.emit_unreachable(); op_stack.start_unreachable(); break;
  806               case opcodes::nop: code_writer.emit_nop(); break;
  807               case opcodes::end: {
  808                  check_in_bounds();
  809                  exit_scope();
  810                  SYS_VM_ASSERT(detail::get_allow_code_after_function_end(_options) ||
 
  811                                !pc_stack.empty() || code.offset() == bounds, wasm_parse_exception, "function too short");
  812                  _nested_checker.on_end(_options);
  813                  break;
  814               }
  815               case opcodes::return_: {
  816                  check_in_bounds();
  818                  auto branch = code_writer.emit_return(compute_depth_change(
label));
 
  819                  handle_branch_target(
label, branch);
 
  820                  op_stack.start_unreachable();
  821               } break;
  822               case opcodes::block: {
  829                                "Invalid type code in block");
  831                  code_writer.emit_block();
  832                  op_stack.push_scope();
  833                  _nested_checker.on_control(_options);
  834               } break;
  835               case opcodes::loop: {
  842                                "Invalid type code in loop");
  843                  auto pos = code_writer.emit_loop();
  844                  pc_stack.push_back({op_stack.depth(), 
expected_result, types::pseudo, 
false, pos});
 
  845                  op_stack.push_scope();
  846                  _nested_checker.on_control(_options);
  847               } break;
  848               case opcodes::if_: {
  849                  check_in_bounds();
  856                                "Invalid type code in if");
  857                  auto branch = code_writer.emit_if();
  858                  op_stack.pop(types::i32);
  860                  op_stack.push_scope();
  861                  _nested_checker.on_control(_options);
  862               } break;
  863               case opcodes::else_: {
  864                  check_in_bounds();
  865                  auto& old_index = pc_stack.back();
  866                  SYS_VM_ASSERT(old_index.is_if, wasm_parse_exception, 
"else outside if");
 
  867                  auto& relocations = std::get<std::vector<branch_t>>(old_index.relocations);
  868                  
  869                  op_stack.pop(old_index.expected_result);
  870                  op_stack.pop_scope();
  871                  op_stack.push_scope();
  872                  
  873                  
  874                  
  875                  relocations[0] = code_writer.emit_else(relocations[0]);
  876                  old_index.is_if = false;
  877                  _nested_checker.on_control(_options);
  878                  break;
  879               }
  880               case opcodes::br: {
  881                  check_in_bounds();
  883                  auto branch = code_writer.emit_br(compute_depth_change(
label));
 
  884                  handle_branch_target(
label, branch);
 
  885                  op_stack.start_unreachable();
  886               } break;
  887               case opcodes::br_if: {
  888                  check_in_bounds();
  890                  op_stack.pop(types::i32);
  891                  auto branch = code_writer.emit_br_if(compute_depth_change(
label));
 
  892                  handle_branch_target(
label, branch);
 
  893               } break;
  894               case opcodes::br_table: {
  895                  check_in_bounds();
  897                  SYS_VM_ASSERT(table_size <= detail::get_max_br_table_elements(_options), wasm_parse_exception, 
"Too many labels in br_table");
 
  899                  op_stack.pop(types::i32);
  900                  auto handler = code_writer.emit_br_table(table_size);
  901                  for (size_t i = 0; i < table_size; i++) {
  903                     auto branch = handler.emit_case(compute_depth_change(
label));
 
  904                     handle_branch_target(
label, branch);
 
  905                     uint8_t one_result = pc_stack[pc_stack.size() - 
label - 1].label_result;
 
  906                     if(i == 0) {
  907                        result_type = one_result;
  908                     } else {
  909                        SYS_VM_ASSERT(result_type == one_result, wasm_parse_exception, 
"br_table labels must have the same type");
 
  910                     }
  911                  }
  913                  auto branch = handler.emit_default(compute_depth_change(
label));
 
  914                  handle_branch_target(
label, branch);
 
  915                  SYS_VM_ASSERT(table_size == 0 || result_type == pc_stack[pc_stack.size() - 
label - 1].label_result,
 
  916                                wasm_parse_exception, "br_table labels must have the same type");
  917                  op_stack.start_unreachable();
  918               } break;
  919               case opcodes::call: {
  920                  check_in_bounds();
  923                  for(
uint32_t i = 0; i < ft.param_types.size(); ++i)
 
  924                     op_stack.pop(ft.param_types[ft.param_types.size() - i - 1]);
  925                  SYS_VM_ASSERT(ft.return_count <= 1, wasm_parse_exception, 
"unsupported");
 
  926                  if(ft.return_count)
  927                     op_stack.push(ft.return_type);
  928                  code_writer.emit_call(ft, funcnum);
  929               } break;
  930               case opcodes::call_indirect: {
  931                  check_in_bounds();
  933                  const func_type& ft = _mod->
types.at(functypeidx);
 
  934                  SYS_VM_ASSERT(_mod->
tables.size() > 0, wasm_parse_exception, 
"call_indirect requires a table");
 
  935                  op_stack.pop(types::i32);
  936                  for(
uint32_t i = 0; i < ft.param_types.size(); ++i)
 
  937                     op_stack.pop(ft.param_types[ft.param_types.size() - i - 1]);
  938                  SYS_VM_ASSERT(ft.return_count <= 1, wasm_parse_exception, 
"unsupported");
 
  939                  if(ft.return_count)
  940                     op_stack.push(ft.return_type);
  941                  code_writer.emit_call_indirect(ft, functypeidx);
  942                  SYS_VM_ASSERT(*code == 0, wasm_parse_exception, 
"call_indirect must end with 0x00.");
 
  943                  code++; 
  944                  break;
  945               }
  946               case opcodes::drop: check_in_bounds(); code_writer.emit_drop(); op_stack.pop(); break;
  947               case opcodes::select: {
  948                  check_in_bounds();
  949                  code_writer.emit_select();
  950                  op_stack.pop(types::i32);
  954                  op_stack.push(t0 != 
any_type? t0 : t1);
 
  955               } break;
  956               case opcodes::get_local: {
  958                  op_stack.push(local_types[local_idx]);
  959                  code_writer.emit_get_local(local_idx);
  960               } break;
  961               case opcodes::set_local: {
  962                  check_in_bounds();
  964                  op_stack.pop(local_types[local_idx]);
  965                  code_writer.emit_set_local(local_idx);
  966               } break;
  967               case opcodes::tee_local: {
  968                  check_in_bounds();
  970                  op_stack.top(local_types[local_idx]);
  971                  code_writer.emit_tee_local(local_idx);
  972               } break;
  973               case opcodes::get_global: {
  975                  op_stack.push(_mod->
globals.at(global_idx).type.content_type);
 
  976                  code_writer.emit_get_global(global_idx);
  977               } break;
  978               case opcodes::set_global: {
  979                  check_in_bounds();
  981                  SYS_VM_ASSERT(_mod->
globals.at(global_idx).type.mutability, wasm_parse_exception, 
"cannot set const global");
 
  982                  op_stack.pop(_mod->
globals.at(global_idx).type.content_type);
 
  983                  code_writer.emit_set_global(global_idx);
  984               } break;
  985#define LOAD_OP(op_name, max_align, type)                            \
  986               case opcodes::op_name: {                              \
  987                  check_in_bounds();                                 \
  988                  SYS_VM_ASSERT(_mod->memories.size() > 0, wasm_parse_exception, "load requires memory"); \
  989                  uint32_t alignment = parse_varuint32(code);        \
  990                  uint32_t offset = parse_varuint32(code);           \
  991                  SYS_VM_ASSERT(alignment <= uint32_t(max_align), wasm_parse_exception, "alignment cannot be greater than size."); \
  992                  SYS_VM_ASSERT(offset <= detail::get_max_memory_offset(_options), wasm_parse_exception, "load offset too large."); \
  993                  op_stack.pop(types::i32);                          \
  994                  op_stack.push(types::type);                        \
  995                  code_writer.emit_ ## op_name( alignment, offset ); \
  996               } break;
  997 
 1012 
 1013#undef LOAD_OP
 1014 
 1015#define STORE_OP(op_name, max_align, type)                           \
 1016               case opcodes::op_name: {                              \
 1017                  check_in_bounds();                                 \
 1018                  SYS_VM_ASSERT(_mod->memories.size() > 0, wasm_parse_exception, "store requires memory"); \
 1019                  uint32_t alignment = parse_varuint32(code);        \
 1020                  uint32_t offset = parse_varuint32(code);           \
 1021                  SYS_VM_ASSERT(alignment <= uint32_t(max_align), wasm_parse_exception, "alignment cannot be greater than size."); \
 1022                  SYS_VM_ASSERT(offset <= detail::get_max_memory_offset(_options), wasm_parse_exception, "store offset too large."); \
 1023                  op_stack.pop(types::type);                         \
 1024                  op_stack.pop(types::i32);                          \
 1025                  code_writer.emit_ ## op_name( alignment, offset ); \
 1026               } break;
 1027 
 1037 
 1038#undef STORE_OP
 1039 
 1040               case opcodes::current_memory:
 1042                  op_stack.push(types::i32);
 1043                  SYS_VM_ASSERT(*code == 0, wasm_parse_exception, 
"memory.size must end with 0x00");
 
 1044                  code++;
 1045                  code_writer.emit_current_memory();
 1046                  break;
 1047               case opcodes::grow_memory:
 1048                  check_in_bounds();
 1050                  op_stack.pop(types::i32);
 1051                  op_stack.push(types::i32);
 1052                  SYS_VM_ASSERT(*code == 0, wasm_parse_exception, 
"memory.grow must end with 0x00");
 
 1053                  code++;
 1054                  code_writer.emit_grow_memory();
 1055                  break;
 1056               case opcodes::i32_const: code_writer.emit_i32_const( 
parse_varint32(code) ); op_stack.push(types::i32); 
break;
 
 1057               case opcodes::i64_const: code_writer.emit_i64_const( 
parse_varint64(code) ); op_stack.push(types::i64); 
break;
 
 1058               case opcodes::f32_const: {
 1060                  op_stack.push(types::f32);
 1061               } break;
 1062               case opcodes::f64_const: {
 1064                  op_stack.push(types::f64);
 1065               } break;
 1066 
 1067#define UNOP(opname) \
 1068               case opcodes::opname: check_in_bounds(); code_writer.emit_ ## opname(); op_stack.pop(types::A); op_stack.push(types::R); break;
 1069#define BINOP(opname) \
 1070               case opcodes::opname: check_in_bounds(); code_writer.emit_ ## opname(); op_stack.pop(types::A); op_stack.pop(types::A); op_stack.push(types::R); break;
 1071#define CASTOP(dst, opname, src)                                         \
 1072               case opcodes::dst ## _ ## opname ## _ ## src: check_in_bounds(); code_writer.emit_ ## dst ## _ ## opname ## _ ## src(); op_stack.pop(types::src); op_stack.push(types::dst); break;
 1073 
 1074#define R i32
 1075#define A i32
 1087#undef A
 1088#define A i64
 1100#undef A
 1101#define A f32
 1108#undef A
 1109#define A f64
 1116#undef A
 1117#undef R
 1118#define R A
 1119#define A i32
 1138#undef A
 1139#define A i64
 1158#undef A
 1159#define A f32
 1174#undef A
 1175#define A f64
 1190#undef A
 1191#undef R
 1192 
 1218 
 1219#undef CASTOP
 1220#undef UNOP
 1221#undef BINOP
 1222               default: 
SYS_VM_ASSERT(
false, wasm_parse_exception, 
"Illegal instruction");
 
 1223            }
 1224         }
 1225         SYS_VM_ASSERT( pc_stack.empty(), wasm_parse_exception, 
"function body too long" );
 
 1227      }
decltype(std::declval< Writer >().emit_if()) branch_t
 
decltype(std::declval< Writer >().emit_end()) label_t
 
T parse_raw(wasm_code_ptr &code)
 
static int32_t parse_varint32(wasm_code_ptr &code)
 
static constexpr uint8_t any_type
 
static int64_t parse_varint64(wasm_code_ptr &code)
 
overloaded(Ts...) -> overloaded< Ts... >
 
float32_t f32_add(float32_t a, float32_t b)
 
float32_t f32_div(float32_t a, float32_t b)
 
bool f32_eq(float32_t a, float32_t b)
 
bool f32_le(float32_t a, float32_t b)
 
bool f32_lt(float32_t a, float32_t b)
 
float32_t f32_mul(float32_t a, float32_t b)
 
float32_t f32_sqrt(float32_t a)
 
float32_t f32_sub(float32_t a, float32_t b)
 
float64_t f64_add(float64_t a, float64_t b)
 
float64_t f64_div(float64_t a, float64_t b)
 
bool f64_eq(float64_t a, float64_t b)
 
bool f64_le(float64_t a, float64_t b)
 
bool f64_lt(float64_t a, float64_t b)
 
float64_t f64_mul(float64_t a, float64_t b)
 
float64_t f64_sqrt(float64_t a)
 
float64_t f64_sub(float64_t a, float64_t b)
 
const unsigned char expected_result[]
 
auto & get_function_type(uint32_t index) const
 
#define CASTOP(dst, opname, src)