==> tests/decode.c <==1/* Decoding: a module of every section kind, and the malformed binaries the format forbids. */
2#include "mesh/check.h"
3#include "wasm/builder.h"
4#include "wasm/decode.h"
5
6#include <stdlib.h>
7#include <string.h>
8
9static char err[256];
10
11static bool dec(const uint8_t *b, size_t n, wasm_module *m) { return wasm_decode(b, n, m, err, sizeof err); }
12
13#define BIN(...) (const uint8_t[]){0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, __VA_ARGS__}
14#define NBIN(...) (8 + sizeof((const uint8_t[]){__VA_ARGS__}))
15#define BAD(msg, ...) \
16 do { \
17 wasm_module m_; \
18 CHECK(!dec(BIN(__VA_ARGS__), NBIN(__VA_ARGS__), &m_)); \
19 CHECK_S(err, msg); \
20 } while (0)
21
22static void full(void) {
23 wasm_builder w = {0};
24 uint32_t t0 = wasm_builder_type(&w, "ii>i");
25 uint32_t t1 = wasm_builder_type(&w, ">");
26 uint32_t imp = wasm_builder_import_func(&w, "mesh", "info", t0);
27 CHECK_U(imp, 0);
28 uint32_t f;
29 wasm_buf *b = wasm_builder_func_add(&w, t0, "iil", &f);
30 wb_op_u32(b, 0x20, 0);
31 wb_op_u32(b, 0x20, 1);
32 wb_op(b, 0x6a);
33 wasm_builder_func_add(&w, t1, "", NULL);
34 wasm_builder_memory(&w, 1, 2, true);
35 wasm_builder_table(&w, 2, 0, false);
36 wb_i32_const(wasm_builder_add_global(&w, WASM_I32, true), 42);
37 wasm_builder_add_export(&w, "add", WASM_EXTERN_FUNC, f);
38 wasm_builder_add_export(&w, "memory", WASM_EXTERN_MEMORY, 0);
39 uint32_t el[] = {1, 2};
40 wasm_builder_elem(&w, 0, el, 2);
41 wasm_builder_data(&w, 16, "hello", 5);
42 wasm_builder_data_passive(&w, "xy", 2);
43 wasm_buf out;
44 wasm_builder_finish(&w, &out);
45 wasm_module m;
46 CHECK(dec(out.data, out.len, &m));
47 CHECK_U(m.ntypes, 2);
48 CHECK_U(m.types[0].nparams, 2);
49 CHECK_U(m.types[0].results[0], WASM_I32);
50 CHECK_U(m.nimports, 1);
51 CHECK_U(m.imports[0].name_len, 4);
52 CHECK(memcmp(m.imports[0].name, "info", 4) == 0);
53 CHECK_U(m.nfuncs, 3);
54 CHECK_U(m.nfunc_imports, 1);
55 CHECK_U(m.funcs[2], 1);
56 CHECK_U(m.ncodes, 2);
57 CHECK_U(m.codes[0].nlocals, 3);
58 CHECK_U(m.codes[0].nlocal_groups, 2);
59 CHECK_U(m.codes[0].body.start[m.codes[0].body.len - 1], 0x0b);
60 CHECK_U(m.nmems, 1);
61 CHECK_U(m.mems[0].min, 1);
62 CHECK_U(m.mems[0].max, 2);
63 CHECK_U(m.ntables, 1);
64 CHECK_U(m.tables[0].elem, WASM_FUNCREF);
65 CHECK_U(m.nglobals, 1);
66 CHECK(m.globals[0].mut);
67 CHECK_U(m.global_inits[0].len, 3);
68 CHECK(wasm_module_export(&m, "add", WASM_EXTERN_FUNC) != NULL);
69 CHECK(wasm_module_export(&m, "add", WASM_EXTERN_MEMORY) == NULL);
70 CHECK_U(m.nelems, 1);
71 CHECK_U(m.elems[0].count, 2);
72 CHECK_U(m.elems[0].funcs[1], 2);
73 CHECK_U(m.ndatas, 2);
74 CHECK_U(m.datas[0].len, 5);
75 CHECK(memcmp(m.datas[0].bytes, "hello", 5) == 0);
76 CHECK_U(m.datas[1].mode, WASM_SEG_PASSIVE);
77 CHECK(m.has_datacount);
78 wasm_module_free(&m);
79
80 /* Every truncation of a valid module is refused, without reading past it. */
81 for (size_t n = 0; n < out.len; n++) {
82 uint8_t *copy = malloc(n ? n : 1);
83 memcpy(copy, out.data, n);
84 /* A cut at a section boundary can be a valid (smaller) module; anywhere else it can't. */
85 if (dec(copy, n, &m)) {
86 CHECK(n == 8 || m.ncodes == 0);
87 wasm_module_free(&m);
88 }
89 free(copy);
90 }
91 wasm_buf_free(&out);
92 wasm_builder_free(&w);
93}
94
95int main(void) {
96 full();
97 wasm_module m;
98 CHECK(dec((const uint8_t[]){0x00, 0x61, 0x73, 0x6d, 1, 0, 0, 0}, 8, &m));
99 CHECK_U(m.nfuncs, 0);
100 wasm_module_free(&m);
101 CHECK(!dec((const uint8_t[]){0x00, 0x61, 0x73, 0x6e, 1, 0, 0, 0}, 8, &m));
102 CHECK_S(err, "magic header not detected: bad magic number (at offset 0x0)");
103 CHECK(!dec((const uint8_t[]){0x00, 0x61, 0x73, 0x6d, 2, 0, 0, 0}, 8, &m));
104 CHECK_S(err, "unknown binary version: 0x2 (at offset 0x4)");
105 /* Order, ids, sizes. */
106 BAD("section out of order (at offset 0xb)", 0x03, 0x01, 0x00, 0x01, 0x01, 0x00);
107 BAD("malformed section id: 14 (at offset 0x8)", 0x0e, 0x00);
108 BAD("section size mismatch: unexpected data at the end of the section (at offset 0xb)", 0x01, 0x02, 0x00, 0x00);
109 BAD("unexpected end-of-file (at offset 0xa)", 0x01, 0x05, 0x00);
110 /* A custom section anywhere, and its name must be UTF-8. */
111 CHECK(dec(BIN(0x00, 0x03, 0x01, 'x', 0xff, 0x01, 0x01, 0x00), NBIN(0x00, 0x03, 0x01, 'x', 0xff, 0x01, 0x01, 0x00), &m));
112 wasm_module_free(&m);
113 BAD("malformed UTF-8 encoding (at offset 0xa)", 0x00, 0x02, 0x01, 0xff);
114 /* Types. */
115 BAD("invalid leading byte in type definition (0x61) (at offset 0xb)", 0x01, 0x04, 0x01, 0x61, 0x00, 0x00);
116 BAD("invalid value type (at offset 0xd)", 0x01, 0x05, 0x01, 0x60, 0x01, 0x00, 0x00);
117 /* A huge count can't allocate. */
118 BAD("types count is out of bounds (at offset 0xf)", 0x01, 0x05, 0xff, 0xff, 0xff, 0xff, 0x0f);
119 /* Functions and code must agree. */
120 BAD("function and code section have inconsistent lengths (at offset 0x14)", 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
121 0x03, 0x02, 0x01, 0x00, 0x0a, 0x01, 0x00);
122 BAD("function and code section have inconsistent lengths (at offset 0x12)", 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
123 0x03, 0x02, 0x01, 0x00);
124 BAD("too many locals (at offset 0x19)", 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x0a, 0x0a,
125 0x01, 0x08, 0x02, 0x01, 0x7f, 0x80, 0x87, 0x03, 0x7f, 0x0b);
126 /* Limits and kinds. */
127 BAD("invalid memory limits flags (at offset 0xb)", 0x05, 0x03, 0x01, 0x08, 0x00);
128 BAD("invalid table resizable limits flags (at offset 0xc)", 0x04, 0x04, 0x01, 0x70, 0x02, 0x00);
129 BAD("malformed reference type (at offset 0xb)", 0x04, 0x04, 0x01, 0x7f, 0x00, 0x00);
130 BAD("invalid leading byte (0x5) for external kind (at offset 0xf)", 0x02, 0x07, 0x01, 0x01, 'm', 0x01, 'n', 0x05,
131 0x00);
132 BAD("malformed mutability (at offset 0xc)", 0x06, 0x06, 0x01, 0x7f, 0x02, 0x41, 0x00, 0x0b);
133 BAD("invalid flags byte in data segment (at offset 0xb)", 0x0b, 0x03, 0x01, 0x03, 0x00);
134 BAD("data count and data section have inconsistent lengths (at offset 0xd)", 0x0c, 0x01, 0x02, 0x0b, 0x01, 0x00);
135 BAD("data count and data section have inconsistent lengths (at offset 0xb)", 0x0c, 0x01, 0x01);
136 BAD("exceptions proposal not enabled (at offset 0x8)", 0x0d, 0x00);
137 /* A constant expression must be well-formed instructions ending in end. */
138 BAD("illegal opcode: 0x6 (at offset 0xd)", 0x06, 0x05, 0x01, 0x7f, 0x00, 0x06, 0x0b);
139 return mesh_check_done();
140}