skip to content
==> 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}