==> 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}