skip to content
==> tests/validate.c <==
1/* Validation: valid bodies of every kind of instruction, and the type errors, index errors and
2 * disabled proposals the spec refuses. */
3#include "mesh/check.h"
4#include "wasm/builder.h"
5#include "wasm/decode.h"
6#include "wasm/validate.h"
7
8#include <string.h>
9
10static char err[256];
11
12/* A module of one function of type sig with locals, whose body bytes are given; validated under f. */
13static bool fn(const char *sig, const char *locals, const uint8_t *body, size_t n, wasm_features f) {
14    wasm_builder w = {0};
15    uint32_t t = wasm_builder_type(&w, sig);
16    wasm_builder_type(&w, "i>ii"); /* type 1: for block type tests */
17    wasm_buf *b = wasm_builder_func_add(&w, t, locals, NULL);
18    wb_bytes(b, body, n);
19    wasm_builder_memory(&w, 1, 0, false);
20    wasm_builder_table(&w, 1, 0, false);
21    wb_i32_const(wasm_builder_add_global(&w, WASM_I32, false), 7);
22    wb_i64_const(wasm_builder_add_global(&w, WASM_I64, true), 7);
23    wasm_buf out;
24    wasm_builder_finish(&w, &out);
25    wasm_module m;
26    bool ok = wasm_decode(out.data, out.len, &m, err, sizeof err);
27    if (ok) {
28        ok = wasm_validate(&m, f, NULL, err, sizeof err);
29        wasm_module_free(&m);
30    }
31    wasm_buf_free(&out);
32    wasm_builder_free(&w);
33    return ok;
34}
35
36#define OK(sig, locals, ...) CHECK(fn(sig, locals, (const uint8_t[]){__VA_ARGS__}, sizeof((const uint8_t[]){__VA_ARGS__}), WASM_F_ALL))
37#define BAD(msg, sig, locals, ...)                                                                                   \
38    do {                                                                                                             \
39        CHECK(!fn(sig, locals, (const uint8_t[]){__VA_ARGS__}, sizeof((const uint8_t[]){__VA_ARGS__}), WASM_F_ALL)); \
40        CHECK(strstr(err, msg) != NULL);                                                                             \
41        if (!strstr(err, msg)) fprintf(stderr, "  got: %s\n", err);                                                  \
42    } while (0)
43#define OFF(feat, msg, sig, locals, ...)                                                                                       \
44    do {                                                                                                                       \
45        CHECK(!fn(sig, locals, (const uint8_t[]){__VA_ARGS__}, sizeof((const uint8_t[]){__VA_ARGS__}), WASM_F_ALL & ~(feat))); \
46        CHECK(strstr(err, msg) != NULL);                                                                                       \
47        if (!strstr(err, msg)) fprintf(stderr, "  got: %s\n", err);                                                            \
48    } while (0)
49
50int main(void) {
51    /* Arithmetic, locals, globals, memory. */
52    OK("ii>i", "", 0x20, 0, 0x20, 1, 0x6a);
53    OK(">", "fd", 0x20, 0, 0x8c, 0x21, 0, 0x20, 1, 0x9f, 0x22, 1, 0x1a);
54    OK(">i", "", 0x23, 0);
55    OK(">", "", 0x42, 1, 0x24, 1);
56    OK("i>l", "", 0x20, 0, 0x29, 3, 8);
57    OK("il>", "", 0x20, 0, 0x20, 1, 0x37, 3, 0);
58    OK(">i", "", 0x3f, 0x00);
59    OK("i>i", "", 0x20, 0, 0x40, 0x00);
60    /* Control: blocks with results, loops, if/else, br, br_if, br_table, return, unreachable. */
61    OK(">i", "", 0x02, 0x7f, 0x41, 1, 0x0b);
62    OK(">i", "", 0x02, 0x7f, 0x41, 1, 0x0c, 0, 0x0b);
63    OK("i>i", "", 0x20, 0, 0x04, 0x7f, 0x41, 1, 0x05, 0x41, 2, 0x0b);
64    OK("i>", "", 0x03, 0x40, 0x20, 0, 0x0d, 0, 0x0b);
65    OK("i>i", "", 0x02, 0x40, 0x02, 0x40, 0x20, 0, 0x0e, 2, 0, 1, 0, 0x0b, 0x0b, 0x41, 0);
66    OK(">i", "", 0x41, 1, 0x0f);
67    OK(">i", "", 0x00);
68    OK(">i", "", 0x00, 0x6a);              /* polymorphic stack after unreachable */
69    OK(">l", "", 0x42, 0, 0x0c, 0, 0x41, 0, 0x1a);  /* dead code after br */
70    OK("i>i", "", 0x20, 0, 0x02, 1, 0x20, 0, 0x0b, 0x6a); /* multi-value block (i32 -> i32 i32) */
71    OK("ii>i", "", 0x20, 0, 0x20, 1, 0x20, 0, 0x1b);           /* select */
72    OK(">", "", 0x41, 0, 0x11, 0, 0x00);                       /* call_indirect type 0 */
73    OK(">i", "", 0x10, 0);                                     /* recursion */
74    /* Sign extension, saturating truncation, bulk memory, reference types. */
75    OK("i>i", "", 0x20, 0, 0xc0);
76    OK("f>i", "", 0x20, 0, 0xfc, 0x00);
77    OK(">", "", 0x41, 0, 0x41, 0, 0x41, 0, 0xfc, 0x0a, 0, 0, 0x41, 0, 0x41, 0, 0x41, 0, 0xfc, 0x0b, 0);
78    OK(">i", "", 0xd0, 0x70, 0xd1);
79    OK(">i", "", 0xfc, 0x10, 0);
80
81    /* Type errors. */
82    BAD("type mismatch: expected i32, found i64", "l>i", "", 0x20, 0, 0x45);
83    BAD("type mismatch: operand stack empty", ">i", "", 0x6a);
84    BAD("values remaining on stack at end of block", ">", "", 0x41, 1);
85    BAD("type mismatch: expected i32, found f32", ">i", "", 0x43, 0, 0, 0, 0);
86    BAD("else branch missing", "i>i", "", 0x20, 0, 0x04, 0x7f, 0x41, 1, 0x0b);
87    BAD("type mismatch: expected i32, found i64", ">i", "", 0x02, 0x7f, 0x42, 1, 0x0c, 0, 0x0b);
88    BAD("select operands have different types", "il>i", "", 0x20, 0, 0x20, 1, 0x20, 0, 0x1b);
89    BAD("br_table target labels have different number of types", "i>i", "", 0x02, 0x7f, 0x02, 0x40, 0x20, 0, 0x0e, 1, 0, 1, 0x0b, 0x41, 0, 0x0b);
90    /* Index errors. */
91    BAD("unknown local 3: local index out of bounds", ">", "", 0x20, 3, 0x1a);
92    BAD("unknown global 9: global index out of bounds", ">i", "", 0x23, 9);
93    BAD("global is immutable", ">", "", 0x41, 1, 0x24, 0);
94    BAD("unknown function 5: function index out of bounds", ">", "", 0x10, 5);
95    BAD("unknown label: branch depth too large", ">", "", 0x0c, 1);
96    BAD("unknown type: type index out of bounds", ">", "", 0x02, 0x09, 0x0b);
97    BAD("alignment must not be larger than natural", "i>i", "", 0x20, 0, 0x28, 3, 0);
98    BAD("undeclared function reference", ">", "", 0xd2, 0, 0x1a);
99    BAD("data count section required", ">", "", 0xfc, 0x09, 0);
100    /* Structure. */
101    BAD("operators remaining after end of function", ">", "", 0x0b, 0x01);
102    BAD("control frames remain at end of function", ">", "", 0x02, 0x40);
103    BAD("else found outside of an `if` block", ">", "", 0x05);
104    /* Proposals that aren't enabled. */
105    OFF(WASM_F_SIGN_EXT, "sign extension operations support is not enabled", "i>i", "", 0x20, 0, 0xc0);
106    OFF(WASM_F_SAT_FLOAT_TO_INT, "saturating float to int conversions support is not enabled", "f>i", "", 0x20, 0, 0xfc, 0x00);
107    OFF(WASM_F_BULK_MEMORY, "bulk memory support is not enabled", ">", "", 0x41, 0, 0x41, 0, 0x41, 0, 0xfc, 0x0b, 0);
108    OFF(WASM_F_REFERENCE_TYPES, "reference types support is not enabled", ">i", "", 0xd0, 0x70, 0xd1);
109    OFF(WASM_F_MULTI_VALUE, "multi-value support is not enabled", "i>i", "", 0x20, 0, 0x02, 1, 0x20, 0, 0x0b, 0x6a);
110    OFF(WASM_F_SIMD, "SIMD support is not enabled", ">", "", 0xfd, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1a);
111    OFF(WASM_F_SIMD, "SIMD support is not enabled", ">", "V", 0x01);
112    OFF(WASM_F_THREADS, "threads support is not enabled", ">", "", 0xfe, 0x03, 0x00);
113    OFF(WASM_F_RELAXED_SIMD, "relaxed SIMD support is not enabled", ">", "", 0xfd, 0x80, 0x02, 0x1a);
114    /* SIMD enabled: walked, not type-checked; but a disabled proposal after it is still found. */
115    OK(">", "", 0xfd, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1a);
116    OFF(WASM_F_THREADS, "threads support is not enabled", ">", "", 0xfd, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1a, 0xfe, 0x03, 0x00);
117
118    /* Module rules. */
119    {
120        wasm_builder w = {0};
121        uint32_t t = wasm_builder_type(&w, ">");
122        wasm_builder_func_add(&w, t, "", NULL);
123        wasm_builder_add_export(&w, "a", WASM_EXTERN_FUNC, 0);
124        wasm_builder_add_export(&w, "a", WASM_EXTERN_FUNC, 0);
125        wasm_buf out;
126        wasm_builder_finish(&w, &out);
127        wasm_module m;
128        CHECK(wasm_decode(out.data, out.len, &m, err, sizeof err));
129        CHECK(!wasm_validate(&m, WASM_F_ALL, NULL, err, sizeof err));
130        CHECK(strstr(err, "duplicate export name") != NULL);
131        wasm_module_free(&m);
132        wasm_buf_free(&out);
133        wasm_builder_free(&w);
134    }
135    {
136        wasm_builder w = {0};
137        wasm_builder_memory(&w, 2, 1, true);
138        wasm_buf out;
139        wasm_builder_finish(&w, &out);
140        wasm_module m;
141        CHECK(wasm_decode(out.data, out.len, &m, err, sizeof err));
142        CHECK(!wasm_validate(&m, WASM_F_ALL, NULL, err, sizeof err));
143        CHECK(strstr(err, "size minimum must not be greater than maximum") != NULL);
144        wasm_module_free(&m);
145        wasm_buf_free(&out);
146        wasm_builder_free(&w);
147    }
148    {
149        /* A global initialised by a non-constant instruction. */
150        wasm_builder w = {0};
151        wasm_buf *g = wasm_builder_add_global(&w, WASM_I32, false);
152        wb_i32_const(g, 1);
153        wb_i32_const(g, 2);
154        wb_op(g, 0x6a);
155        wasm_buf out;
156        wasm_builder_finish(&w, &out);
157        wasm_module m;
158        CHECK(wasm_decode(out.data, out.len, &m, err, sizeof err));
159        CHECK(wasm_validate(&m, WASM_F_ALL, NULL, err, sizeof err));
160        CHECK(!wasm_validate(&m, WASM_F_ALL & ~WASM_F_EXTENDED_CONST, NULL, err, sizeof err));
161        CHECK(strstr(err, "extended constant expressions support is not enabled") != NULL);
162        wasm_module_free(&m);
163        wasm_buf_free(&out);
164        wasm_builder_free(&w);
165    }
166    return mesh_check_done();
167}