Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
parser.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <sysio/vm/allocator.hpp>
4#include <sysio/vm/constants.hpp>
5#include <sysio/vm/exceptions.hpp>
6#include <sysio/vm/leb128.hpp>
7#include <sysio/vm/options.hpp>
8#include <sysio/vm/sections.hpp>
9#include <sysio/vm/types.hpp>
10#include <sysio/vm/utils.hpp>
11#include <sysio/vm/vector.hpp>
12#include <sysio/vm/debug_info.hpp>
13
14#include <algorithm>
15#include <cassert>
16#include <cstdint>
17#include <utility>
18#include <variant>
19#include <vector>
20
21namespace sysio { namespace vm {
22
23 namespace detail {
24
25 static constexpr unsigned get_size_for_type(uint8_t type) {
26 switch(type) {
27 case types::i32:
28 case types::f32:
29 return 4;
30 case types::i64:
31 case types::f64:
32 return 8;
33 default: return 0;
34 }
35 }
36
37 template<typename Options, typename Enable = void>
38 struct max_mutable_globals_checker {
39 constexpr void on_mutable_global(const Options&, uint8_t) {}
40 };
41
42 template<typename Options>
43 using max_mutable_globals_t = decltype(std::declval<Options>().max_mutable_global_bytes);
44
45 template<typename Options>
46 struct max_mutable_globals_checker<Options, std::void_t<max_mutable_globals_t<Options>>> {
47 static_assert(std::is_unsigned_v<std::decay_t<max_mutable_globals_t<Options>>>, "max_mutable_globals must be an unsigned integer type");
48 void on_mutable_global(const Options& options, uint8_t type) {
49 unsigned size = get_size_for_type(type);
50 _counter += size;
51 SYS_VM_ASSERT(_counter <= options.max_mutable_global_bytes && _counter >= size, wasm_parse_exception, "mutable globals exceeded limit");
52 }
53 std::decay_t<max_mutable_globals_t<Options>> _counter = 0;
54 };
55
56#define PARSER_OPTION(name, default_, type) \
57 template<typename Options> \
58 type get_ ## name(const Options& options, long) { (void)options; return default_; } \
59 template<typename Options> \
60 auto get_ ## name(const Options& options, int) -> decltype(options.name) { \
61 return options.name; \
62 } \
63 template<typename Options> \
64 type get_ ## name(const Options& options) { return detail::get_ ## name(options, 0); }
65
66#define MAX_ELEMENTS(name, default_)\
67 PARSER_OPTION(name, default_, std::uint32_t)
68
69 MAX_ELEMENTS(max_table_elements, 0xFFFFFFFFu)
70 MAX_ELEMENTS(max_section_elements, 0xFFFFFFFFu)
71
72 MAX_ELEMENTS(max_type_section_elements, detail::get_max_section_elements(options))
73 MAX_ELEMENTS(max_import_section_elements, detail::get_max_section_elements(options))
74 MAX_ELEMENTS(max_function_section_elements, detail::get_max_section_elements(options))
75 MAX_ELEMENTS(max_global_section_elements, detail::get_max_section_elements(options))
76 MAX_ELEMENTS(max_export_section_elements, detail::get_max_section_elements(options))
77 MAX_ELEMENTS(max_element_section_elements, detail::get_max_section_elements(options))
78 MAX_ELEMENTS(max_data_section_elements, detail::get_max_section_elements(options))
79
80 MAX_ELEMENTS(max_element_segment_elements, 0xFFFFFFFFu)
81 MAX_ELEMENTS(max_data_segment_bytes, 0xFFFFFFFFu)
82
83 PARSER_OPTION(max_linear_memory_init, 0xFFFFFFFFFFFFFFFFu, std::uint64_t)
85
86 template<typename Options, typename Enable = void>
88 explicit max_func_local_bytes_checker(const Options&, const func_type& /*ft*/) {}
89 void on_local(const Options&, std::uint8_t, const std::uint32_t) {}
90 void push_stack(const Options& /*options*/, std::uint8_t /*type*/) {}
91 void pop_stack(std::uint8_t /*type*/) {}
94 static constexpr bool is_defined = false;
95 };
96 template<typename Options>
97 struct max_func_local_bytes_checker<Options, std::void_t<decltype(std::declval<Options>().max_func_local_bytes)>> {
98 explicit max_func_local_bytes_checker(const Options& options, const func_type& ft) {
99 if ((detail::get_max_func_local_bytes_flags(options) & max_func_local_bytes_flags_t::params) != (max_func_local_bytes_flags_t)0) {
100 for(std::uint32_t i = 0; i < ft.param_types.size(); ++i) {
101 on_type(options, ft.param_types.at(i));
102 }
103 }
104 }
105 void on_type(const Options& options, std::uint8_t type) {
106 unsigned size = get_size_for_type(type);
107 _count += size;
108 SYS_VM_ASSERT(_count <= options.max_func_local_bytes && _count >= size, wasm_parse_exception, "local variable limit exceeded");
109 }
110 void on_local(const Options& options, std::uint8_t type, std::uint32_t count) {
111 if ((detail::get_max_func_local_bytes_flags(options) & max_func_local_bytes_flags_t::locals) != (max_func_local_bytes_flags_t)0) {
112 uint64_t size = get_size_for_type(type);
113 size *= count;
114 _count += size;
115 SYS_VM_ASSERT(_count <= options.max_func_local_bytes && _count >= size, wasm_parse_exception, "local variable limit exceeded");
116 }
117 }
118 std::decay_t<decltype(std::declval<Options>().max_func_local_bytes)> _count = 0;
119 static constexpr bool is_defined = true;
120 };
121 template<typename Options>
122 constexpr auto get_max_func_local_bytes_no_stack_c(int) -> std::enable_if_t<std::is_pointer_v<decltype(&Options::max_func_local_bytes_flags)>, bool>
123 { return (Options::max_func_local_bytes_flags & max_func_local_bytes_flags_t::stack) == (max_func_local_bytes_flags_t)0; }
124 template<typename Options>
125 constexpr auto get_max_func_local_bytes_no_stack_c(long) -> bool { return false; }
126
127 template<typename Options, typename Enable = void>
128 struct max_func_local_bytes_stack_checker : max_func_local_bytes_checker<Options> {
130 void push_stack(const Options& options, std::uint8_t type) {
131 if(unreachable_depth == 0 && (detail::get_max_func_local_bytes_flags(options) & max_func_local_bytes_flags_t::stack) != (max_func_local_bytes_flags_t)0) {
132 this->on_type(options, type);
133 }
134 }
135 void pop_stack(const Options& options, std::uint8_t type) {
136 if(unreachable_depth == 0 && (detail::get_max_func_local_bytes_flags(options) & max_func_local_bytes_flags_t::stack) != (max_func_local_bytes_flags_t)0) {
137 this->_count -= get_size_for_type(type);
138 }
139 }
142 }
145 }
146 std::uint32_t unreachable_depth = 0;
147 };
148 template<typename Options>
149 struct max_func_local_bytes_stack_checker<Options, std::enable_if_t<!max_func_local_bytes_checker<Options>::is_defined ||
150 get_max_func_local_bytes_no_stack_c<Options>(0)>> {
152 void push_stack(const Options& /*options*/, std::uint8_t /*type*/) {}
153 void pop_stack(const Options& /*options*/, std::uint8_t /*type*/) {}
156 };
157
158 MAX_ELEMENTS(max_local_sets, 0xFFFFFFFFu)
159 MAX_ELEMENTS(max_nested_structures, 0xFFFFFFFFu)
160 MAX_ELEMENTS(max_br_table_elements, 0xFFFFFFFFu)
161
162 // Matches the behavior of sysio::chain::wasm_validations::nested_validator
163 template<typename Options, typename Enable = void>
164 struct sysio_max_nested_structures_checker {
165 void on_control(const Options&) {}
166 void on_end(const Options&) {}
167 };
168 template<typename Options>
169 struct sysio_max_nested_structures_checker<Options, std::void_t<decltype(std::declval<Options>().sysio_max_nested_structures)>> {
170 void on_control(const Options& options) {
171 ++_count;
172 SYS_VM_ASSERT(_count <= options.sysio_max_nested_structures, wasm_parse_exception, "Nested depth exceeded");
173 }
174 void on_end(const Options& options) {
175 if(_count == 0) ++_count;
176 else --_count;
177 }
178 std::decay_t<decltype(std::declval<Options>().sysio_max_nested_structures)> _count = 0;
179 };
180
181 MAX_ELEMENTS(max_symbol_bytes, 0xFFFFFFFFu)
182 MAX_ELEMENTS(max_memory_offset, 0xFFFFFFFFu)
183 MAX_ELEMENTS(max_code_bytes, 0xFFFFFFFFu)
184 MAX_ELEMENTS(max_pages, 0xFFFFFFFFu)
186
187 PARSER_OPTION(forbid_export_mutable_globals, false, bool);
188 PARSER_OPTION(allow_code_after_function_end, false, bool);
189 PARSER_OPTION(allow_u32_limits_flags, false, bool);
190 PARSER_OPTION(allow_invalid_empty_local_set, false, bool);
191
192 PARSER_OPTION(allow_zero_blocktype, false, bool)
193
194 PARSER_OPTION(parse_custom_section_name, false, bool);
195
196#undef MAX_ELEMENTS
197#undef PARSER_OPTION
198
199 }
200
201 template <typename Writer, typename Options = default_options, typename DebugInfo = null_debug_info>
202 class binary_parser {
203 public:
204 explicit binary_parser(growable_allocator& alloc, const Options& options = Options{}) : _allocator(alloc), _options(options) {}
205
206 template <typename T>
208
209 static inline uint8_t parse_varuint1(wasm_code_ptr& code) { return varuint<1>(code).to(); }
210
211 static inline uint8_t parse_varuint7(wasm_code_ptr& code) { return varuint<7>(code).to(); }
212
213 static inline uint32_t parse_varuint32(wasm_code_ptr& code) { return varuint<32>(code).to(); }
214
215 static inline int8_t parse_varint7(wasm_code_ptr& code) { return varint<7>(code).to(); }
216
217 static inline int32_t parse_varint32(wasm_code_ptr& code) { return varint<32>(code).to(); }
218
219 static inline int64_t parse_varint64(wasm_code_ptr& code) { return varint<64>(code).to(); }
220
222 unsigned char ch = *code++;
223 if (ch < 0x80) {
224 return 1;
225 } else if(ch < 0xE0) {
226 SYS_VM_ASSERT((ch & 0xC0) == 0xC0, wasm_parse_exception, "invalid utf8 encoding");
227 unsigned char b2 = *code++;
228 SYS_VM_ASSERT((b2 & 0xC0) == 0x80, wasm_parse_exception, "invalid utf8 encoding");
229 uint32_t code_point =
230 (static_cast<uint32_t>(ch - 0xC0u) << 6u) +
231 (static_cast<uint32_t>(b2 - 0x80u));
232 SYS_VM_ASSERT(0x80 <= code_point && code_point < 0x800, wasm_parse_exception, "invalid utf8 encoding");
233 return 2;
234 } else if(ch < 0xF0) {
235 unsigned char b2 = *code++;
236 SYS_VM_ASSERT((b2 & 0xC0) == 0x80, wasm_parse_exception, "invalid utf8 encoding");
237 unsigned char b3 = *code++;
238 SYS_VM_ASSERT((b3 & 0xC0) == 0x80, wasm_parse_exception, "invalid utf8 encoding");
239 uint32_t code_point =
240 (static_cast<uint32_t>(ch - 0xE0u) << 12u) +
241 (static_cast<uint32_t>(b2 - 0x80u) << 6u) +
242 (static_cast<uint32_t>(b3 - 0x80u));
243 SYS_VM_ASSERT((0x800 <= code_point && code_point < 0xD800) ||
244 (0xE000 <= code_point && code_point < 0x10000),
245 wasm_parse_exception, "invalid utf8 encoding");
246 return 3;
247 } else if (ch < 0xF8) {
248 unsigned char b2 = *code++;
249 SYS_VM_ASSERT((b2 & 0xC0) == 0x80, wasm_parse_exception, "invalid utf8 encoding");
250 unsigned char b3 = *code++;
251 SYS_VM_ASSERT((b3 & 0xC0) == 0x80, wasm_parse_exception, "invalid utf8 encoding");
252 unsigned char b4 = *code++;
253 SYS_VM_ASSERT((b4 & 0xC0) == 0x80, wasm_parse_exception, "invalid utf8 encoding");
254 uint32_t code_point =
255 (static_cast<uint32_t>(ch - 0xF0u) << 18u) +
256 (static_cast<uint32_t>(b2 - 0x80u) << 12u) +
257 (static_cast<uint32_t>(b3 - 0x80u) << 6u) +
258 (static_cast<uint32_t>(b4 - 0x80u));
259 SYS_VM_ASSERT((0x10000 <= code_point && code_point < 0x110000),
260 wasm_parse_exception, "invalid utf8 encoding");
261 return 4;
262 }
263 SYS_VM_ASSERT(false, wasm_parse_exception, "invalid utf8 encoding");
264 }
265
267 while(bytes != 0) {
269 }
270 }
271
273 auto len = parse_varuint32(code);
274 SYS_VM_ASSERT(len <= max_size, wasm_parse_exception, "name too long");
275 auto guard = code.scoped_shrink_bounds(len);
276 auto result = guarded_vector<uint8_t>{ _allocator, len };
277 result.copy(code.raw(), len);
279 return result;
280 }
281
282 template<typename T>
284 static_assert(std::is_arithmetic_v<T>, "Can only read builtin types");
285 auto guard = code.scoped_shrink_bounds(sizeof(T));
286 T result;
287 memcpy(&result, code.raw(), sizeof(T));
288 code += sizeof(T);
289 return result;
290 }
291
292 inline module& parse_module(wasm_code& code, module& mod, DebugInfo& debug) {
293 wasm_code_ptr cp(code.data(), code.size());
294 parse_module(cp, code.size(), mod, debug);
295 return mod;
296 }
297
298 inline module& parse_module2(wasm_code_ptr& code_ptr, size_t sz, module& mod, DebugInfo& debug) {
299 parse_module(code_ptr, sz, mod, debug);
300 return mod;
301 }
302
303 void parse_module(wasm_code_ptr& code_ptr, size_t sz, module& mod, DebugInfo& debug) {
304 _mod = &mod;
305 SYS_VM_ASSERT(parse_magic(code_ptr) == constants::magic, wasm_parse_exception, "magic number did not match");
306 SYS_VM_ASSERT(parse_version(code_ptr) == constants::version, wasm_parse_exception,
307 "version number did not match");
308 uint8_t highest_section_id = 0;
309 for (;;) {
310 if (code_ptr.offset() == sz)
311 break;
312 auto id = parse_section_id(code_ptr);
313 auto len = parse_section_payload_len(code_ptr);
314
315 SYS_VM_ASSERT(id == 0 || id > highest_section_id, wasm_parse_exception, "section out of order");
316 highest_section_id = std::max(highest_section_id, id);
317
318 auto section_guard = code_ptr.scoped_consume_items(len);
319
320 switch (id) {
321 case section_id::custom_section: parse_custom(code_ptr); break;
322 case section_id::type_section: parse_section<section_id::type_section>(code_ptr, mod.types); break;
323 case section_id::import_section: parse_section<section_id::import_section>(code_ptr, mod.imports); break;
324 case section_id::function_section:
325 parse_section<section_id::function_section>(code_ptr, mod.functions);
326 mod.normalize_types();
327 break;
328 case section_id::table_section: parse_section<section_id::table_section>(code_ptr, mod.tables); break;
329 case section_id::memory_section:
330 parse_section<section_id::memory_section>(code_ptr, mod.memories);
331 break;
332 case section_id::global_section: parse_section<section_id::global_section>(code_ptr, mod.globals); break;
333 case section_id::export_section:
334 parse_section<section_id::export_section>(code_ptr, mod.exports);
335 validate_exports();
336 break;
337 case section_id::start_section: parse_section<section_id::start_section>(code_ptr, mod.start); break;
338 case section_id::element_section:
339 parse_section<section_id::element_section>(code_ptr, mod.elements);
340 break;
341 case section_id::code_section: parse_section<section_id::code_section>(code_ptr, mod.code); break;
342 case section_id::data_section: parse_section<section_id::data_section>(code_ptr, mod.data); break;
343 default: SYS_VM_ASSERT(false, wasm_parse_exception, "error invalid section id");
344 }
345 }
346 SYS_VM_ASSERT(_mod->code.size() == _mod->functions.size(), wasm_parse_exception, "code section must have the same size as the function section" );
347
348 debug.set(std::move(imap));
349 debug.relocate(_allocator.get_code_start());
350 }
351
353 return parse_raw<uint32_t>(code);
354 }
356 return parse_raw<uint32_t>(code);
357 }
358 inline uint8_t parse_section_id(wasm_code_ptr& code) { return *code++; }
360 return parse_varuint32(code);
361 }
362
363 inline void parse_custom(wasm_code_ptr& code) {
364 auto section_name = parse_utf8_string(code, 0xFFFFFFFFu); // ignored, but needs to be validated
365 if(detail::get_parse_custom_section_name(_options) &&
366 section_name.size() == 4 && std::memcmp(section_name.raw(), "name", 4) == 0) {
367 parse_name_section(code);
368 } else {
369 // skip to the end of the section
370 code += code.bounds() - code.offset();
371 }
372 }
373
375 for(uint32_t i = 0; i < map.size(); ++i) {
376 map[i].idx = parse_varuint32(code);
377 map[i].name = parse_utf8_string(code, 0xFFFFFFFFu);
378 }
379 }
380
382 _mod->names = _allocator.alloc<name_section>(1);
383 new (_mod->names) name_section;
384 if(code.bounds() == code.offset()) return;
385 if(*code == 0) {
386 ++code;
387 auto subsection_guard = code.scoped_consume_items(parse_varuint32(code));
388 _mod->names->module_name = _allocator.alloc<guarded_vector<uint8_t>>(1);
389 new (_mod->names->module_name) guarded_vector<uint8_t>(parse_utf8_string(code, 0xFFFFFFFFu));
390 }
391 if(code.bounds() == code.offset()) return;
392 if(*code == 1) {
393 ++code;
394 auto subsection_guard = code.scoped_consume_items(parse_varuint32(code));
395 uint32_t size = parse_varuint32(code);
396 _mod->names->function_names = _allocator.alloc<guarded_vector<name_assoc>>(1);
397 new (_mod->names->function_names) guarded_vector<name_assoc>(_allocator, size);
398 parse_name_map(code, *_mod->names->function_names);
399 }
400 if(code.bounds() == code.offset()) return;
401 if(*code == 2) {
402 ++code;
403 auto subsection_guard = code.scoped_consume_items(parse_varuint32(code));
404 uint32_t size = parse_varuint32(code);
405 _mod->names->local_names = _allocator.alloc<guarded_vector<indirect_name_assoc>>(1);
406 new (_mod->names->local_names) guarded_vector<indirect_name_assoc>(_allocator, size);
407 for(uint32_t i = 0; i < size; ++i) {
408 auto& [idx,namemap] = (*_mod->names->local_names)[i];
409 idx = parse_varuint32(code);
410 uint32_t local_size = parse_varuint32(code);
411 namemap = guarded_vector<name_assoc>(_allocator, local_size);
412 parse_name_map(code, namemap);
413 }
414 }
415 if(code.bounds() == code.offset()) return;
416 SYS_VM_ASSERT(false, wasm_parse_exception, "Invalid subsection Id");
417 }
418
420 entry.module_str = parse_utf8_string(code, detail::get_max_symbol_bytes(_options));
421 entry.field_str = parse_utf8_string(code, detail::get_max_symbol_bytes(_options));
422 entry.kind = (external_kind)(*code++);
423 auto type = parse_varuint32(code);
424 switch ((uint8_t)entry.kind) {
425 case external_kind::Function:
426 entry.type.func_t = type;
427 SYS_VM_ASSERT(type < _mod->types.size(), wasm_parse_exception, "Invalid function type");
428 break;
429 default: SYS_VM_ASSERT(false, wasm_unsupported_import_exception, "only function imports are supported");
430 }
431 }
432
434 if (detail::get_allow_u32_limits_flags(_options)) {
435 return parse_varuint32(code) & 0x1;
436 } else {
437 SYS_VM_ASSERT(*code == 0x0 || *code == 0x1, wasm_parse_exception, "invalid flags");
438 return *code++;
439 }
440 }
441
443 tt.element_type = *code++;
444 SYS_VM_ASSERT(tt.element_type == types::anyfunc, wasm_parse_exception, "table must have type anyfunc");
445 tt.limits.flags = parse_flags(code);
446 tt.limits.initial = parse_varuint32(code);
447 if (tt.limits.flags) {
448 tt.limits.maximum = parse_varuint32(code);
449 SYS_VM_ASSERT(tt.limits.initial <= tt.limits.maximum, wasm_parse_exception, "table max size less than min size");
450 }
451 SYS_VM_ASSERT(tt.limits.initial <= detail::get_max_table_elements(_options), wasm_parse_exception, "table size exceeds limit");
452 tt.table = decltype(tt.table){ _allocator, tt.limits.initial };
453 for (uint32_t i = 0; i < tt.limits.initial; i++) tt.table[i] = std::numeric_limits<uint32_t>::max();
454 }
455
457 uint8_t ct = *code++;
458 gv.type.content_type = ct;
459 SYS_VM_ASSERT(ct == types::i32 || ct == types::i64 || ct == types::f32 || ct == types::f64,
460 wasm_parse_exception, "invalid global content type");
461
462 gv.type.mutability = parse_varuint1(code);
463 if(gv.type.mutability)
464 on_mutable_global(ct);
465 parse_init_expr(code, gv.init, ct);
466 gv.current = gv.init;
467 }
468
470 mt.limits.flags = parse_flags(code);
471 mt.limits.initial = parse_varuint32(code);
472 // Implementation limits
473 SYS_VM_ASSERT(mt.limits.initial <= detail::get_max_pages(_options), wasm_parse_exception, "initial memory out of range");
474 // WASM specification
475 SYS_VM_ASSERT(mt.limits.initial <= 65536u, wasm_parse_exception, "initial memory out of range");
476 if (mt.limits.flags) {
477 mt.limits.maximum = parse_varuint32(code);
478 SYS_VM_ASSERT(mt.limits.maximum >= mt.limits.initial, wasm_parse_exception, "maximum must be at least minimum");
479 SYS_VM_ASSERT(mt.limits.maximum <= 65536u, wasm_parse_exception, "maximum memory out of range");
480 }
481 }
482
484 entry.field_str = parse_utf8_string(code, detail::get_max_symbol_bytes(_options));
485 entry.kind = (external_kind)(*code++);
486 entry.index = parse_varuint32(code);
487 switch(entry.kind) {
488 case external_kind::Function: SYS_VM_ASSERT(entry.index < _mod->get_functions_total(), wasm_parse_exception, "function export out of range"); break;
489 case external_kind::Table: SYS_VM_ASSERT(entry.index < _mod->tables.size(), wasm_parse_exception, "table export out of range"); break;
490 case external_kind::Memory: SYS_VM_ASSERT(entry.index < _mod->memories.size(), wasm_parse_exception, "memory export out of range"); break;
491 case external_kind::Global:
492 SYS_VM_ASSERT(entry.index < _mod->globals.size(), wasm_parse_exception, "global export out of range");
493 SYS_VM_ASSERT(!detail::get_forbid_export_mutable_globals(_options) || !_mod->globals.at(entry.index).type.mutability,
494 wasm_parse_exception, "cannot export mutable globals");
495 break;
496 default: SYS_VM_ASSERT(false, wasm_parse_exception, "Unknown export kind"); break;
497 }
498 }
499
501 ft.form = *code++;
502 SYS_VM_ASSERT(ft.form == 0x60, wasm_parse_exception, "invalid function type");
503 decltype(ft.param_types) param_types = { _allocator, parse_varuint32(code) };
504 for (size_t i = 0; i < param_types.size(); i++) {
505 uint8_t pt = *code++;
506 param_types.at(i) = pt;
507 SYS_VM_ASSERT(pt == types::i32 || pt == types::i64 || pt == types::f32 || pt == types::f64,
508 wasm_parse_exception, "invalid function param type");
509 }
510 ft.param_types = std::move(param_types);
511 ft.return_count = *code++;
512 SYS_VM_ASSERT(ft.return_count < 2, wasm_parse_exception, "invalid function return count");
513 if (ft.return_count > 0) {
514 uint8_t rt = *code++;
515 ft.return_type = rt;
516 SYS_VM_ASSERT(rt == types::i32 || rt == types::i64 || rt == types::f32 || rt == types::f64,
517 wasm_parse_exception, "invalid function return type");
518 }
519 }
520
522 table_type* tt = nullptr;
523 for (std::size_t i = 0; i < _mod->tables.size(); i++) {
524 if (_mod->tables[i].element_type == types::anyfunc)
525 tt = &(_mod->tables[i]);
526 }
527 SYS_VM_ASSERT(tt != nullptr, wasm_parse_exception, "table not declared");
528 es.index = parse_varuint32(code);
529 SYS_VM_ASSERT(es.index == 0, wasm_parse_exception, "only table index of 0 is supported");
530 parse_init_expr(code, es.offset, types::i32);
531 uint32_t size = parse_varuint32(code);
532 SYS_VM_ASSERT(size <= detail::get_max_element_segment_elements(_options), wasm_parse_exception, "elem segment too large");
533 decltype(es.elems) elems = { _allocator, size };
534 for (uint32_t i = 0; i < size; i++) {
535 uint32_t index = parse_varuint32(code);
536 elems.at(i) = index;
537 SYS_VM_ASSERT(index < _mod->get_functions_total(), wasm_parse_exception, "elem for undefined function");
538 }
539 uint32_t offset = static_cast<uint32_t>(es.offset.value.i32);
540 if ( static_cast<uint64_t>(size) + offset <= tt->table.size() ) {
541 std::memcpy(tt->table.raw() + offset, elems.raw(), size * sizeof(uint32_t));
542 } else {
543 _mod->error = "elem out of range";
544 }
545 es.elems = std::move(elems);
546 }
547
549 ie.opcode = *code++;
550 switch (ie.opcode) {
551 case opcodes::i32_const:
552 ie.value.i32 = parse_varint32(code);
553 SYS_VM_ASSERT(type == types::i32, wasm_parse_exception, "expected i32 initializer");
554 break;
555 case opcodes::i64_const:
556 ie.value.i64 = parse_varint64(code);
557 SYS_VM_ASSERT(type == types::i64, wasm_parse_exception, "expected i64 initializer");
558 break;
559 case opcodes::f32_const:
560 ie.value.f32 = parse_raw<uint32_t>(code);
561 SYS_VM_ASSERT(type == types::f32, wasm_parse_exception, "expected f32 initializer");
562 break;
563 case opcodes::f64_const:
564 ie.value.f64 = parse_raw<uint64_t>(code);
565 SYS_VM_ASSERT(type == types::f64, wasm_parse_exception, "expected f64 initializer");
566 break;
567 default:
568 SYS_VM_ASSERT(false, wasm_parse_exception,
569 "initializer expression can only acception i32.const, i64.const, f32.const and f64.const");
570 }
571 SYS_VM_ASSERT((*code++) == opcodes::end, wasm_parse_exception, "no end op found");
572 }
573
574 void parse_function_body(wasm_code_ptr& code, function_body& fb, std::size_t idx) {
575 fb.size = parse_varuint32(code);
576 SYS_VM_ASSERT(fb.size <= detail::get_max_code_bytes(_options), wasm_parse_exception, "Function body too large");
577 const auto& before = code.offset();
578 const auto& local_cnt = parse_varuint32(code);
579 _current_function_index++;
580 SYS_VM_ASSERT(local_cnt <= detail::get_max_local_sets(_options), wasm_parse_exception, "Number of local sets exceeds limit");
581 decltype(fb.locals) locals = { _allocator, local_cnt };
582 func_type& ft = _mod->types.at(_mod->functions.at(idx));
583 detail::max_func_local_bytes_checker<Options> local_checker(_options, ft);
584 // parse the local entries
585 for (size_t i = 0; i < local_cnt; i++) {
586 auto count = parse_varuint32(code);
587 auto type = *code++;
588 if (detail::get_allow_invalid_empty_local_set(_options) && count == 0) type = types::i32;
589 SYS_VM_ASSERT(type == types::i32 || type == types::i64 || type == types::f32 || type == types::f64,
590 wasm_parse_exception, "invalid local type");
591 local_checker.on_local(_options, type, count);
592 locals.at(i).count = count;
593 locals.at(i).type = type;
594 }
595 fb.locals = std::move(locals);
596
597 fb.size -= code.offset() - before;
598 auto guard = code.scoped_shrink_bounds(fb.size);
599 _function_bodies.emplace_back(wasm_code_ptr{code.raw(), fb.size}, local_checker);
600
601 code += fb.size-1;
602 SYS_VM_ASSERT(detail::get_allow_code_after_function_end(_options) || *code == 0x0B,
603 wasm_parse_exception, "failed parsing function body, expected 'end'");
604 ++code;
605 }
606
607 // The control stack holds either address of the target of the
608 // label (for backward jumps) or a list of instructions to be
609 // updated (for forward jumps).
610 //
611 // Inside an if: The first element refers to the `if` and should
612 // jump to `else`. The remaining elements should branch to `end`
613 using label_t = decltype(std::declval<Writer>().emit_end());
614 using branch_t = decltype(std::declval<Writer>().emit_if());
615 struct pc_element_t {
619 bool is_if;
620 std::variant<label_t, std::vector<branch_t>> relocations;
621 };
622
623 static constexpr uint8_t any_type = 0x82;
626 : local_bytes_checker(local_bytes_checker), options(options) {}
627 std::vector<uint8_t> state = { scope_tag };
628 static constexpr uint8_t unreachable_tag = 0x80;
629 static constexpr uint8_t scope_tag = 0x81;
630 uint32_t operand_depth = 0;
631 uint32_t maximum_operand_depth = 0;
633 const Options& options;
634 void push(uint8_t type) {
635 assert(type != unreachable_tag && type != scope_tag);
636 assert(type == types::i32 || type == types::i64 || type == types::f32 || type == types::f64 || type == any_type);
637 SYS_VM_ASSERT(operand_depth < std::numeric_limits<uint32_t>::max(), wasm_parse_exception, "integer overflow in operand depth");
638 ++operand_depth;
639 maximum_operand_depth = std::max(operand_depth, maximum_operand_depth);
640 state.push_back(type);
641 local_bytes_checker.push_stack(options, type);
642 }
643 void pop(uint8_t expected) {
644 assert(expected != unreachable_tag && expected != scope_tag);
645 if(expected == types::pseudo) return;
646 SYS_VM_ASSERT(!state.empty(), wasm_parse_exception, "unexpected pop");
647 if (state.back() != unreachable_tag) {
648 SYS_VM_ASSERT(state.back() == expected || state.back() == any_type, wasm_parse_exception, "wrong type");
649 local_bytes_checker.pop_stack(options, expected);
650 --operand_depth;
651 state.pop_back();
652 }
653 }
655 SYS_VM_ASSERT(!state.empty() && state.back() != scope_tag, wasm_parse_exception, "unexpected pop");
656 if (state.back() == unreachable_tag)
657 return any_type;
658 else {
659 uint8_t result = state.back();
660 --operand_depth;
661 local_bytes_checker.pop_stack(options, result);
662 state.pop_back();
663 return result;
664 }
665 }
666 void top(uint8_t expected) {
667 // Constrain the top of the stack if it was any_type or unreachable_tag.
668 pop(expected);
669 push(expected);
670 }
672 while(!state.empty() && state.back() != scope_tag) {
673 if (state.back() != unreachable_tag)
674 --operand_depth;
675 state.pop_back();
676 }
677 local_bytes_checker.push_unreachable();
678 state.push_back(unreachable_tag);
679 }
680 void push_scope() {
681 state.push_back(scope_tag);
682 }
683 void pop_scope(uint8_t expected_result = types::pseudo) {
684 pop(expected_result);
685 SYS_VM_ASSERT(!state.empty(), wasm_parse_exception, "unexpected end");
686 if (state.back() == unreachable_tag) {
687 local_bytes_checker.pop_unreachable();
688 state.pop_back();
689 }
690 SYS_VM_ASSERT(state.back() == scope_tag, wasm_parse_exception, "unexpected end");
691 state.pop_back();
692 if (expected_result != types::pseudo) {
693 push(expected_result);
694 }
695 }
696 void finish() {
697 if (!state.empty() && state.back() == unreachable_tag) {
698 state.pop_back();
699 }
700 SYS_VM_ASSERT(state.empty(), wasm_parse_exception, "stack not empty at scope end");
701 }
702 uint32_t depth() const { return operand_depth; }
703 };
704
705 struct local_types_t {
707 _ft(ft), _locals(locals_arg) {
708 uint32_t count = ft.param_types.size();
709 _boundaries.push_back(count);
710 for (uint32_t i = 0; i < locals_arg.size(); ++i) {
711 // This test cannot overflow.
712 SYS_VM_ASSERT (count <= 0xFFFFFFFFu - locals_arg[i].count, wasm_parse_exception, "too many locals");
713 count += locals_arg[i].count;
714 _boundaries.push_back(count);
715 }
716 }
717 uint8_t operator[](uint32_t local_idx) const {
718 SYS_VM_ASSERT(local_idx < _boundaries.back(), wasm_parse_exception, "undefined local");
719 auto pos = std::upper_bound(_boundaries.begin(), _boundaries.end(), local_idx);
720 if (pos == _boundaries.begin())
721 return _ft.param_types[local_idx];
722 else
723 return _locals[pos - _boundaries.begin() - 1].type;
724 }
726 uint64_t total = _boundaries.back();
727 return total - _ft.param_types.size();
728 }
731 std::vector<uint32_t> _boundaries;
732 };
733
735 Writer& code_writer, const func_type& ft, const local_types_t& local_types) {
736
737 // Initialize the control stack with the current function as the sole element
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),
742 ft.return_count ? ft.return_type : static_cast<uint32_t>(types::pseudo),
743 false,
744 std::vector<branch_t>{}}};
745
746 // writes the continuation of a label to address. If the continuation
747 // is not yet available, address will be recorded in the relocations
748 // list for label.
749 auto handle_branch_target = [&](uint32_t label, branch_t address) {
750 SYS_VM_ASSERT(label < pc_stack.size(), wasm_parse_exception, "invalid label");
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 // Returns the number of operands that need to be popped when
758 // branching to label. If the label has a return value it will
759 // be counted in this, and the high bit will be set to signal
760 // its presence.
761 auto compute_depth_change = [&](uint32_t label) -> uint32_t {
762 SYS_VM_ASSERT(label < pc_stack.size(), wasm_parse_exception, "invalid label");
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 // FIXME: Reusing the high bit imposes an additional constraint
767 // on the maximum depth of the operand stack. This isn't an
768 // actual problem right now, because the stack is hard-coded
769 // to 8192 elements, but it would be better to avoid spreading
770 // this assumption around the code.
771 result |= 0x80000000;
772 op_stack.top(branch_target.label_result);
773 }
774 return result;
775 };
776
777 // Handles branches to the end of the scope and pops the pc_stack
778 auto exit_scope = [&]() {
779 // There must be at least one element
780 SYS_VM_ASSERT(pc_stack.size(), wasm_parse_exception, "unexpected end instruction");
781 // an if with an empty else cannot have a return value
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();
817 uint32_t label = pc_stack.size() - 1;
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: {
823 uint32_t expected_result = *code++;
824 if(detail::get_allow_zero_blocktype(_options) && expected_result == 0)
825 expected_result = types::pseudo;
826 SYS_VM_ASSERT(expected_result == types::i32 || expected_result == types::i64 ||
827 expected_result == types::f32 || expected_result == types::f64 ||
828 expected_result == types::pseudo, wasm_parse_exception,
829 "Invalid type code in block");
830 pc_stack.push_back({op_stack.depth(), expected_result, expected_result, false, std::vector<branch_t>{}});
831 code_writer.emit_block();
832 op_stack.push_scope();
833 _nested_checker.on_control(_options);
834 } break;
835 case opcodes::loop: {
836 uint32_t expected_result = *code++;
837 if(detail::get_allow_zero_blocktype(_options) && expected_result == 0)
838 expected_result = types::pseudo;
839 SYS_VM_ASSERT(expected_result == types::i32 || expected_result == types::i64 ||
840 expected_result == types::f32 || expected_result == types::f64 ||
841 expected_result == types::pseudo, wasm_parse_exception,
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();
850 uint32_t expected_result = *code++;
851 if(detail::get_allow_zero_blocktype(_options) && expected_result == 0)
852 expected_result = types::pseudo;
853 SYS_VM_ASSERT(expected_result == types::i32 || expected_result == types::i64 ||
854 expected_result == types::f32 || expected_result == types::f64 ||
855 expected_result == types::pseudo, wasm_parse_exception,
856 "Invalid type code in if");
857 auto branch = code_writer.emit_if();
858 op_stack.pop(types::i32);
859 pc_stack.push_back({op_stack.depth(), expected_result, expected_result, true, std::vector{branch}});
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 // reset the operand stack to the same state as the if
869 op_stack.pop(old_index.expected_result);
870 op_stack.pop_scope();
871 op_stack.push_scope();
872 // Overwrite the branch from the `if` with the `else`.
873 // We're left with a normal relocation list where everything
874 // branches to the corresponding `end`
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();
882 uint32_t label = parse_varuint32(code);
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();
889 uint32_t label = parse_varuint32(code);
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();
896 size_t table_size = parse_varuint32(code);
897 SYS_VM_ASSERT(table_size <= detail::get_max_br_table_elements(_options), wasm_parse_exception, "Too many labels in br_table");
898 uint8_t result_type = 0;
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++) {
902 uint32_t label = parse_varuint32(code);
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 }
912 uint32_t label = parse_varuint32(code);
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();
921 uint32_t funcnum = parse_varuint32(code);
922 const func_type& ft = _mod->get_function_type(funcnum);
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();
932 uint32_t functypeidx = parse_varuint32(code);
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++; // 0x00
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);
951 uint8_t t0 = op_stack.pop();
952 uint8_t t1 = op_stack.pop();
953 SYS_VM_ASSERT(t0 == t1 || t0 == any_type || t1 == any_type, wasm_parse_exception, "incorrect types for select");
954 op_stack.push(t0 != any_type? t0 : t1);
955 } break;
956 case opcodes::get_local: {
957 uint32_t local_idx = parse_varuint32(code);
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();
963 uint32_t local_idx = parse_varuint32(code);
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();
969 uint32_t local_idx = parse_varuint32(code);
970 op_stack.top(local_types[local_idx]);
971 code_writer.emit_tee_local(local_idx);
972 } break;
973 case opcodes::get_global: {
974 uint32_t global_idx = parse_varuint32(code);
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();
980 uint32_t global_idx = parse_varuint32(code);
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
998 LOAD_OP(i32_load, 2, i32)
999 LOAD_OP(i64_load, 3, i64)
1000 LOAD_OP(f32_load, 2, f32)
1001 LOAD_OP(f64_load, 3, f64)
1002 LOAD_OP(i32_load8_s, 0, i32)
1003 LOAD_OP(i32_load16_s, 1, i32)
1004 LOAD_OP(i32_load8_u, 0, i32)
1005 LOAD_OP(i32_load16_u, 1, i32)
1006 LOAD_OP(i64_load8_s, 0, i64)
1007 LOAD_OP(i64_load16_s, 1, i64)
1008 LOAD_OP(i64_load32_s, 2, i64)
1009 LOAD_OP(i64_load8_u, 0, i64)
1010 LOAD_OP(i64_load16_u, 1, i64)
1011 LOAD_OP(i64_load32_u, 2, i64)
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
1028 STORE_OP(i32_store, 2, i32)
1029 STORE_OP(i64_store, 3, i64)
1030 STORE_OP(f32_store, 2, f32)
1031 STORE_OP(f64_store, 3, f64)
1032 STORE_OP(i32_store8, 0, i32)
1033 STORE_OP(i32_store16, 1, i32)
1034 STORE_OP(i64_store8, 0, i64)
1035 STORE_OP(i64_store16, 1, i64)
1036 STORE_OP(i64_store32, 2, i64)
1037
1038#undef STORE_OP
1039
1040 case opcodes::current_memory:
1041 SYS_VM_ASSERT(_mod->memories.size() != 0, wasm_parse_exception, "memory.size requires 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();
1049 SYS_VM_ASSERT(_mod->memories.size() != 0, wasm_parse_exception, "memory.grow requires memory");
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: {
1059 code_writer.emit_f32_const( parse_raw<float>(code) );
1060 op_stack.push(types::f32);
1061 } break;
1062 case opcodes::f64_const: {
1063 code_writer.emit_f64_const( parse_raw<double>(code) );
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
1076 UNOP(i32_eqz)
1077 BINOP(i32_eq)
1078 BINOP(i32_ne)
1079 BINOP(i32_lt_s)
1080 BINOP(i32_lt_u)
1081 BINOP(i32_gt_s)
1082 BINOP(i32_gt_u)
1083 BINOP(i32_le_s)
1084 BINOP(i32_le_u)
1085 BINOP(i32_ge_s)
1086 BINOP(i32_ge_u)
1087#undef A
1088#define A i64
1089 UNOP(i64_eqz)
1090 BINOP(i64_eq)
1091 BINOP(i64_ne)
1092 BINOP(i64_lt_s)
1093 BINOP(i64_lt_u)
1094 BINOP(i64_gt_s)
1095 BINOP(i64_gt_u)
1096 BINOP(i64_le_s)
1097 BINOP(i64_le_u)
1098 BINOP(i64_ge_s)
1099 BINOP(i64_ge_u)
1100#undef A
1101#define A f32
1102 BINOP(f32_eq)
1103 BINOP(f32_ne)
1104 BINOP(f32_lt)
1105 BINOP(f32_gt)
1106 BINOP(f32_le)
1107 BINOP(f32_ge)
1108#undef A
1109#define A f64
1110 BINOP(f64_eq)
1111 BINOP(f64_ne)
1112 BINOP(f64_lt)
1113 BINOP(f64_gt)
1114 BINOP(f64_le)
1115 BINOP(f64_ge)
1116#undef A
1117#undef R
1118#define R A
1119#define A i32
1120 UNOP(i32_clz)
1121 UNOP(i32_ctz)
1122 UNOP(i32_popcnt)
1123 BINOP(i32_add)
1124 BINOP(i32_sub)
1125 BINOP(i32_mul)
1126 BINOP(i32_div_s)
1127 BINOP(i32_div_u)
1128 BINOP(i32_rem_s)
1129 BINOP(i32_rem_u)
1130 BINOP(i32_and)
1131 BINOP(i32_or)
1132 BINOP(i32_xor)
1133 BINOP(i32_shl)
1134 BINOP(i32_shr_s)
1135 BINOP(i32_shr_u)
1136 BINOP(i32_rotl)
1137 BINOP(i32_rotr)
1138#undef A
1139#define A i64
1140 UNOP(i64_clz)
1141 UNOP(i64_ctz)
1142 UNOP(i64_popcnt)
1143 BINOP(i64_add)
1144 BINOP(i64_sub)
1145 BINOP(i64_mul)
1146 BINOP(i64_div_s)
1147 BINOP(i64_div_u)
1148 BINOP(i64_rem_s)
1149 BINOP(i64_rem_u)
1150 BINOP(i64_and)
1151 BINOP(i64_or)
1152 BINOP(i64_xor)
1153 BINOP(i64_shl)
1154 BINOP(i64_shr_s)
1155 BINOP(i64_shr_u)
1156 BINOP(i64_rotl)
1157 BINOP(i64_rotr)
1158#undef A
1159#define A f32
1160 UNOP(f32_abs)
1161 UNOP(f32_neg)
1162 UNOP(f32_ceil)
1163 UNOP(f32_floor)
1164 UNOP(f32_trunc)
1165 UNOP(f32_nearest)
1166 UNOP(f32_sqrt)
1167 BINOP(f32_add)
1168 BINOP(f32_sub)
1169 BINOP(f32_mul)
1170 BINOP(f32_div)
1171 BINOP(f32_min)
1172 BINOP(f32_max)
1173 BINOP(f32_copysign)
1174#undef A
1175#define A f64
1176 UNOP(f64_abs)
1177 UNOP(f64_neg)
1178 UNOP(f64_ceil)
1179 UNOP(f64_floor)
1180 UNOP(f64_trunc)
1181 UNOP(f64_nearest)
1182 UNOP(f64_sqrt)
1183 BINOP(f64_add)
1184 BINOP(f64_sub)
1185 BINOP(f64_mul)
1186 BINOP(f64_div)
1187 BINOP(f64_min)
1188 BINOP(f64_max)
1189 BINOP(f64_copysign)
1190#undef A
1191#undef R
1192
1193 CASTOP(i32, wrap, i64)
1194 CASTOP(i32, trunc_s, f32)
1195 CASTOP(i32, trunc_u, f32)
1196 CASTOP(i32, trunc_s, f64)
1197 CASTOP(i32, trunc_u, f64)
1198 CASTOP(i64, extend_s, i32)
1199 CASTOP(i64, extend_u, i32)
1200 CASTOP(i64, trunc_s, f32)
1201 CASTOP(i64, trunc_u, f32)
1202 CASTOP(i64, trunc_s, f64)
1203 CASTOP(i64, trunc_u, f64)
1204 CASTOP(f32, convert_s, i32)
1205 CASTOP(f32, convert_u, i32)
1206 CASTOP(f32, convert_s, i64)
1207 CASTOP(f32, convert_u, i64)
1208 CASTOP(f32, demote, f64)
1209 CASTOP(f64, convert_s, i32)
1210 CASTOP(f64, convert_u, i32)
1211 CASTOP(f64, convert_s, i64)
1212 CASTOP(f64, convert_u, i64)
1213 CASTOP(f64, promote, f32)
1214 CASTOP(i32, reinterpret, f32)
1215 CASTOP(i64, reinterpret, f64)
1216 CASTOP(f32, reinterpret, i32)
1217 CASTOP(f64, reinterpret, i64)
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" );
1226 _mod->maximum_stack = std::max(_mod->maximum_stack, static_cast<uint64_t>(op_stack.maximum_operand_depth) + local_types.locals_count());
1227 }
1228
1230 SYS_VM_ASSERT(_mod->memories.size() != 0, wasm_parse_exception, "data requires memory");
1231 ds.index = parse_varuint32(code);
1232 parse_init_expr(code, ds.offset, types::i32);
1233 auto len = parse_varuint32(code);
1234 SYS_VM_ASSERT(len <= detail::get_max_data_segment_bytes(_options), wasm_parse_exception, "data segment too large.");
1235 SYS_VM_ASSERT(static_cast<uint64_t>(static_cast<uint32_t>(ds.offset.value.i32)) + len <= detail::get_max_linear_memory_init(_options),
1236 wasm_parse_exception, "out-of-bounds data section");
1237 auto guard = code.scoped_shrink_bounds(len);
1238 ds.data = decltype(ds.data){ _allocator, len};
1239 ds.data.copy(code.raw(), len);
1240 code += len;
1241 }
1242
1243 template <typename Elem, typename ParseFunc>
1244 inline void parse_section_impl(wasm_code_ptr& code, vec<Elem>& elems, std::uint32_t max_elements, ParseFunc&& elem_parse) {
1245 auto count = parse_varuint32(code);
1246 SYS_VM_ASSERT(count <= max_elements, wasm_parse_exception, "number of section elements exceeded limit");
1247 elems = vec<Elem>{ _allocator, count };
1248 for (size_t i = 0; i < count; i++) { elem_parse(code, elems.at(i), i); }
1249 }
1250
1251 template <uint8_t id>
1252 inline void parse_section(wasm_code_ptr& code,
1253 vec<typename std::enable_if_t<id == section_id::type_section, func_type>>& elems) {
1254 parse_section_impl(code, elems, detail::get_max_type_section_elements(_options),
1255 [&](wasm_code_ptr& code, func_type& ft, std::size_t /*idx*/) { parse_func_type(code, ft); });
1256 }
1257 template <uint8_t id>
1258 inline void parse_section(wasm_code_ptr& code,
1259 vec<typename std::enable_if_t<id == section_id::import_section, import_entry>>& elems) {
1260 parse_section_impl(code, elems, detail::get_max_import_section_elements(_options),
1261 [&](wasm_code_ptr& code, import_entry& ie, std::size_t /*idx*/) { parse_import_entry(code, ie); });
1262 }
1263 template <uint8_t id>
1264 inline void parse_section(wasm_code_ptr& code,
1265 vec<typename std::enable_if_t<id == section_id::function_section, uint32_t>>& elems) {
1266 parse_section_impl(code, elems, detail::get_max_function_section_elements(_options),
1267 [&](wasm_code_ptr& code, uint32_t& elem, std::size_t /*idx*/) { elem = parse_varuint32(code); });
1268 }
1269 template <uint8_t id>
1270 inline void parse_section(wasm_code_ptr& code,
1271 vec<typename std::enable_if_t<id == section_id::table_section, table_type>>& elems) {
1272 parse_section_impl(code, elems, 1,
1273 [&](wasm_code_ptr& code, table_type& tt, std::size_t /*idx*/) { parse_table_type(code, tt); });
1274 }
1275 template <uint8_t id>
1276 inline void parse_section(wasm_code_ptr& code,
1277 vec<typename std::enable_if_t<id == section_id::memory_section, memory_type>>& elems) {
1278 parse_section_impl(code, elems, 1, [&](wasm_code_ptr& code, memory_type& mt, std::size_t idx) {
1279 SYS_VM_ASSERT(idx == 0, wasm_parse_exception, "only one memory is permitted");
1280 parse_memory_type(code, mt);
1281 });
1282 }
1283 template <uint8_t id>
1284 inline void
1286 vec<typename std::enable_if_t<id == section_id::global_section, global_variable>>& elems) {
1287 parse_section_impl(code, elems, detail::get_max_global_section_elements(_options),
1288 [&](wasm_code_ptr& code, global_variable& gv, std::size_t /*idx*/) { parse_global_variable(code, gv); });
1289 }
1290 template <uint8_t id>
1291 inline void parse_section(wasm_code_ptr& code,
1292 vec<typename std::enable_if_t<id == section_id::export_section, export_entry>>& elems) {
1293 parse_section_impl(code, elems, detail::get_max_export_section_elements(_options),
1294 [&](wasm_code_ptr& code, export_entry& ee, std::size_t /*idx*/) { parse_export_entry(code, ee); });
1295 }
1296 template <uint8_t id>
1297 inline void parse_section(wasm_code_ptr& code,
1298 typename std::enable_if_t<id == section_id::start_section, uint32_t>& start) {
1299 start = parse_varuint32(code);
1300 const func_type& ft = _mod->get_function_type(start);
1301 SYS_VM_ASSERT(ft.return_count == 0 && ft.param_types.size() == 0, wasm_parse_exception, "wrong type for start");
1302 }
1303 template <uint8_t id>
1304 inline void
1306 vec<typename std::enable_if_t<id == section_id::element_section, elem_segment>>& elems) {
1307 parse_section_impl(code, elems, detail::get_max_element_section_elements(_options),
1308 [&](wasm_code_ptr& code, elem_segment& es, std::size_t /*idx*/) { parse_elem_segment(code, es); });
1309 }
1310 template <uint8_t id>
1311 inline void parse_section(wasm_code_ptr& code,
1312 vec<typename std::enable_if_t<id == section_id::code_section, function_body>>& elems) {
1313 const void* code_start = code.raw() - code.offset();
1314 parse_section_impl(code, elems, detail::get_max_function_section_elements(_options),
1315 [&](wasm_code_ptr& code, function_body& fb, std::size_t idx) { parse_function_body(code, fb, idx); });
1316 SYS_VM_ASSERT( elems.size() == _mod->functions.size(), wasm_parse_exception, "code section must have the same size as the function section" );
1317 Writer code_writer(_allocator, code.bounds() - code.offset(), *_mod);
1318 imap.on_code_start(code_writer.get_base_addr(), code_start);
1319 for (size_t i = 0; i < _function_bodies.size(); i++) {
1320 function_body& fb = _mod->code[i];
1321 func_type& ft = _mod->types.at(_mod->functions.at(i));
1322 local_types_t local_types(ft, fb.locals);
1323 imap.on_function_start(code_writer.get_addr(), _function_bodies[i].first.raw());
1324 code_writer.emit_prologue(ft, fb.locals, i);
1325 parse_function_body_code(_function_bodies[i].first, fb.size, _function_bodies[i].second, code_writer, ft, local_types);
1326 code_writer.emit_epilogue(ft, fb.locals, i);
1327 code_writer.finalize(fb);
1328 }
1329 imap.on_code_end(code_writer.get_addr(), code.raw());
1330 }
1331 template <uint8_t id>
1332 inline void parse_section(wasm_code_ptr& code,
1333 vec<typename std::enable_if_t<id == section_id::data_section, data_segment>>& elems) {
1334 parse_section_impl(code, elems, detail::get_max_data_section_elements(_options),
1335 [&](wasm_code_ptr& code, data_segment& ds, std::size_t /*idx*/) { parse_data_segment(code, ds); });
1336 }
1337
1338 template <size_t N>
1339 varint<N> parse_varint(const wasm_code& code, size_t index) {
1340 varint<N> result(0);
1341 result.set(code, index);
1342 return result;
1343 }
1344
1345 template <size_t N>
1346 varuint<N> parse_varuint(const wasm_code& code, size_t index) {
1347 varuint<N> result(0);
1348 result.set(code, index);
1349 return result;
1350 }
1351
1353 _globals_checker.on_mutable_global(_options, type);
1354 }
1355
1356 void validate_exports() const {
1357 std::vector<const guarded_vector<uint8_t>*> export_names;
1358 export_names.reserve(_mod->exports.size());
1359 for (uint32_t i = 0; i < _mod->exports.size(); ++i) {
1360 export_names.push_back(&_mod->exports[i].field_str);
1361 }
1362 std::sort(export_names.begin(), export_names.end(), [](auto* lhs, auto* rhs) {
1363 return std::lexicographical_compare(lhs->raw(), lhs->raw() + lhs->size(), rhs->raw(), rhs->raw() + rhs->size());
1364 });
1365 auto it = std::adjacent_find(export_names.begin(), export_names.end(), [](auto* lhs, auto* rhs) {
1366 return lhs->size() == rhs->size() && std::equal(lhs->raw(), lhs->raw() + lhs->size(), rhs->raw());
1367 });
1368 SYS_VM_ASSERT(it == export_names.end(), wasm_parse_exception, "duplicate export name");
1369 }
1370
1371 private:
1372 growable_allocator& _allocator;
1373 Options _options;
1374 module* _mod; // non-owning weak pointer
1375 int64_t _current_function_index = -1;
1376 uint64_t _maximum_function_stack_usage = 0; // non-parameter locals + stack
1377 std::vector<std::pair<wasm_code_ptr, detail::max_func_local_bytes_stack_checker<Options>>> _function_bodies;
1380 typename DebugInfo::builder imap;
1381 };
1382}} // namespace sysio::vm
JSON writer.
Definition writer.h:89
varint< N > parse_varint(const wasm_code &code, size_t index)
Definition parser.hpp:1339
uint8_t parse_flags(wasm_code_ptr &code)
Definition parser.hpp:433
void parse_elem_segment(wasm_code_ptr &code, elem_segment &es)
Definition parser.hpp:521
void on_mutable_global(uint8_t type)
Definition parser.hpp:1352
uint32_t parse_magic(wasm_code_ptr &code)
Definition parser.hpp:352
decltype(std::declval< Writer >().emit_if()) branch_t
Definition parser.hpp:614
void parse_name_section(wasm_code_ptr &code)
Definition parser.hpp:381
void parse_function_body(wasm_code_ptr &code, function_body &fb, std::size_t idx)
Definition parser.hpp:574
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::table_section, table_type > > &elems)
Definition parser.hpp:1270
int validate_utf8_code_point(wasm_code_ptr &code)
Definition parser.hpp:221
static uint8_t parse_varuint7(wasm_code_ptr &code)
Definition parser.hpp:211
void parse_module(wasm_code_ptr &code_ptr, size_t sz, module &mod, DebugInfo &debug)
Definition parser.hpp:303
void validate_utf8_string(wasm_code_ptr &code, uint32_t bytes)
Definition parser.hpp:266
void parse_import_entry(wasm_code_ptr &code, import_entry &entry)
Definition parser.hpp:419
void parse_export_entry(wasm_code_ptr &code, export_entry &entry)
Definition parser.hpp:483
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::code_section, function_body > > &elems)
Definition parser.hpp:1311
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::export_section, export_entry > > &elems)
Definition parser.hpp:1291
decltype(std::declval< Writer >().emit_end()) label_t
Definition parser.hpp:613
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::function_section, uint32_t > > &elems)
Definition parser.hpp:1264
static int8_t parse_varint7(wasm_code_ptr &code)
Definition parser.hpp:215
T parse_raw(wasm_code_ptr &code)
Definition parser.hpp:283
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::element_section, elem_segment > > &elems)
Definition parser.hpp:1305
static uint32_t parse_varuint32(wasm_code_ptr &code)
Definition parser.hpp:213
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::memory_section, memory_type > > &elems)
Definition parser.hpp:1276
static int32_t parse_varint32(wasm_code_ptr &code)
Definition parser.hpp:217
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::data_section, data_segment > > &elems)
Definition parser.hpp:1332
void parse_section(wasm_code_ptr &code, typename std::enable_if_t< id==section_id::start_section, uint32_t > &start)
Definition parser.hpp:1297
void parse_init_expr(wasm_code_ptr &code, init_expr &ie, uint8_t type)
Definition parser.hpp:548
uint32_t parse_version(wasm_code_ptr &code)
Definition parser.hpp:355
varuint< N > parse_varuint(const wasm_code &code, size_t index)
Definition parser.hpp:1346
void parse_function_body_code(wasm_code_ptr &code, size_t bounds, const detail::max_func_local_bytes_stack_checker< Options > &local_bytes_checker, Writer &code_writer, const func_type &ft, const local_types_t &local_types)
Definition parser.hpp:734
static uint8_t parse_varuint1(wasm_code_ptr &code)
Definition parser.hpp:209
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::type_section, func_type > > &elems)
Definition parser.hpp:1252
void validate_exports() const
Definition parser.hpp:1356
void parse_table_type(wasm_code_ptr &code, table_type &tt)
Definition parser.hpp:442
static int64_t parse_varint64(wasm_code_ptr &code)
Definition parser.hpp:219
void parse_memory_type(wasm_code_ptr &code, memory_type &mt)
Definition parser.hpp:469
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::global_section, global_variable > > &elems)
Definition parser.hpp:1285
void parse_data_segment(wasm_code_ptr &code, data_segment &ds)
Definition parser.hpp:1229
void parse_section(wasm_code_ptr &code, vec< typename std::enable_if_t< id==section_id::import_section, import_entry > > &elems)
Definition parser.hpp:1258
guarded_vector< uint8_t > parse_utf8_string(wasm_code_ptr &code, std::uint32_t max_size)
Definition parser.hpp:272
binary_parser(growable_allocator &alloc, const Options &options=Options{})
Definition parser.hpp:204
void parse_custom(wasm_code_ptr &code)
Definition parser.hpp:363
void parse_section_impl(wasm_code_ptr &code, vec< Elem > &elems, std::uint32_t max_elements, ParseFunc &&elem_parse)
Definition parser.hpp:1244
void parse_name_map(wasm_code_ptr &code, guarded_vector< name_assoc > &map)
Definition parser.hpp:374
void parse_func_type(wasm_code_ptr &code, func_type &ft)
Definition parser.hpp:500
module & parse_module(wasm_code &code, module &mod, DebugInfo &debug)
Definition parser.hpp:292
uint32_t parse_section_payload_len(wasm_code_ptr &code)
Definition parser.hpp:359
void parse_global_variable(wasm_code_ptr &code, global_variable &gv)
Definition parser.hpp:456
uint8_t parse_section_id(wasm_code_ptr &code)
Definition parser.hpp:358
constexpr void push_back(U &&val)
Definition vector.hpp:35
constexpr T & at(size_t i)
Definition vector.hpp:57
constexpr size_t size() const
Definition vector.hpp:78
constexpr bool to()
Definition leb128.hpp:156
constexpr bool to()
Definition leb128.hpp:77
bool debug
int * count
Definition name.hpp:106
constexpr auto get_max_func_local_bytes_no_stack_c(int) -> std::enable_if_t< std::is_pointer_v< decltype(&Options::max_func_local_bytes_flags)>, bool >
Definition parser.hpp:122
decltype(std::declval< Options >().max_mutable_global_bytes) max_mutable_globals_t
Definition parser.hpp:43
external_kind
Definition types.hpp:22
std::vector< uint8_t > wasm_code
Definition types.hpp:147
max_func_local_bytes_flags_t
Definition options.hpp:7
#define T(meth, val, expected)
float32_t f32_add(float32_t a, float32_t b)
Definition f32_add.c:43
float32_t f32_div(float32_t a, float32_t b)
Definition f32_div.c:44
bool f32_eq(float32_t a, float32_t b)
Definition f32_eq.c:44
bool f32_le(float32_t a, float32_t b)
Definition f32_le.c:43
bool f32_lt(float32_t a, float32_t b)
Definition f32_lt.c:43
float32_t f32_mul(float32_t a, float32_t b)
Definition f32_mul.c:44
float32_t f32_sqrt(float32_t a)
Definition f32_sqrt.c:44
float32_t f32_sub(float32_t a, float32_t b)
Definition f32_sub.c:43
float64_t f64_add(float64_t a, float64_t b)
Definition f64_add.c:43
float64_t f64_div(float64_t a, float64_t b)
Definition f64_div.c:44
bool f64_eq(float64_t a, float64_t b)
Definition f64_eq.c:44
bool f64_le(float64_t a, float64_t b)
Definition f64_le.c:43
bool f64_lt(float64_t a, float64_t b)
Definition f64_lt.c:43
float64_t f64_mul(float64_t a, float64_t b)
Definition f64_mul.c:44
float64_t f64_sqrt(float64_t a)
Definition f64_sqrt.c:44
float64_t f64_sub(float64_t a, float64_t b)
Definition f64_sub.c:43
const unsigned char expected_result[]
Definition ssh.c:73
signed __int64 int64_t
Definition stdint.h:135
unsigned int uint32_t
Definition stdint.h:126
signed int int32_t
Definition stdint.h:123
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
signed char int8_t
Definition stdint.h:121
const guarded_vector< local_entry > & _locals
Definition parser.hpp:730
local_types_t(const func_type &ft, const guarded_vector< local_entry > &locals_arg)
Definition parser.hpp:706
std::vector< uint32_t > _boundaries
Definition parser.hpp:731
uint8_t operator[](uint32_t local_idx) const
Definition parser.hpp:717
operand_stack_type_tracker(const detail::max_func_local_bytes_stack_checker< Options > local_bytes_checker, const Options &options)
Definition parser.hpp:625
detail::max_func_local_bytes_stack_checker< Options > local_bytes_checker
Definition parser.hpp:632
void pop_scope(uint8_t expected_result=types::pseudo)
Definition parser.hpp:683
std::variant< label_t, std::vector< branch_t > > relocations
Definition parser.hpp:620
max_func_local_bytes_checker(const Options &, const func_type &)
Definition parser.hpp:88
void on_local(const Options &, std::uint8_t, const std::uint32_t)
Definition parser.hpp:89
void push_stack(const Options &, std::uint8_t)
Definition parser.hpp:90
void push_stack(const Options &options, std::uint8_t type)
Definition parser.hpp:130
constexpr max_func_local_bytes_stack_checker(const max_func_local_bytes_checker< Options > &base)
Definition parser.hpp:129
void pop_stack(const Options &options, std::uint8_t type)
Definition parser.hpp:135
constexpr void on_mutable_global(const Options &, uint8_t)
Definition parser.hpp:39
guarded_vector< uint32_t > elems
Definition types.hpp:114
Definition types.hpp:105
external_kind kind
Definition types.hpp:107
guarded_vector< uint8_t > field_str
Definition types.hpp:106
uint32_t index
Definition types.hpp:108
uint8_t return_count
Definition types.hpp:45
value_type form
Definition types.hpp:43
guarded_vector< value_type > param_types
Definition types.hpp:44
value_type return_type
Definition types.hpp:46
guarded_vector< local_entry > locals
Definition types.hpp:136
value_type content_type
Definition types.hpp:70
auto scoped_consume_items(std::size_t n)
Definition types.hpp:98
guarded_vector< uint8_t > module_str
Definition types.hpp:99
import_type type
Definition types.hpp:102
guarded_vector< uint8_t > field_str
Definition types.hpp:100
external_kind kind
Definition types.hpp:101
expr_value value
Definition types.hpp:66
resizable_limits limits
Definition types.hpp:87
guarded_vector< uint32_t > functions
Definition types.hpp:171
uint32_t start
Definition types.hpp:168
guarded_vector< import_entry > imports
Definition types.hpp:170
guarded_vector< global_variable > globals
Definition types.hpp:174
guarded_vector< elem_segment > elements
Definition types.hpp:176
guarded_vector< export_entry > exports
Definition types.hpp:175
guarded_vector< table_type > tables
Definition types.hpp:172
guarded_vector< memory_type > memories
Definition types.hpp:173
void normalize_types()
Definition types.hpp:240
guarded_vector< func_type > types
Definition types.hpp:169
guarded_vector< function_body > code
Definition types.hpp:177
guarded_vector< data_segment > data
Definition types.hpp:178
resizable_limits limits
Definition types.hpp:82
guarded_vector< uint32_t > table
Definition types.hpp:83
elem_type element_type
Definition types.hpp:81
#define SYS_VM_ASSERT(expr, exc_type, msg)
Definition exceptions.hpp:8
#define CASTOP(dst, opname, src)
#define MAX_ELEMENTS(name, default_)
Definition parser.hpp:66
#define PARSER_OPTION(name, default_, type)
Definition parser.hpp:56
#define UNOP
#define LOAD_OP
#define STORE_OP
#define BINOP
yh_object_type type
Definition yubihsm.h:672
char * label
yubihsm_pkcs11_object_template template
size_t len
memcpy((char *) pInfo->slotDescription, s, l)