/src/WasmEdge/lib/validator/validator.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "validator/validator.h" |
5 | | |
6 | | #include "ast/section.h" |
7 | | #include "common/errinfo.h" |
8 | | #include "common/hash.h" |
9 | | |
10 | | #include <numeric> |
11 | | #include <string> |
12 | | #include <unordered_set> |
13 | | |
14 | | using namespace std::literals; |
15 | | |
16 | | namespace WasmEdge { |
17 | | namespace Validator { |
18 | | |
19 | | namespace { |
20 | | |
21 | | // One-shot builder for the pre-defined core function SubTypes. |
22 | | AST::SubType makeCoreFuncType(std::initializer_list<TypeCode> Params, |
23 | 19.4k | std::initializer_list<TypeCode> Results) { |
24 | 19.4k | AST::FunctionType FT; |
25 | 19.4k | for (auto T : Params) { |
26 | 19.4k | FT.getParamTypes().emplace_back(T); |
27 | 19.4k | } |
28 | 19.4k | for (auto T : Results) { |
29 | 9.70k | FT.getReturnTypes().emplace_back(T); |
30 | 9.70k | } |
31 | 19.4k | AST::SubType ST; |
32 | 19.4k | ST.getCompositeType().setFunctionType(std::move(FT)); |
33 | 19.4k | return ST; |
34 | 19.4k | } |
35 | | |
36 | | static constexpr uint32_t MaxSubtypeDepth = 63; |
37 | | static constexpr uint32_t Unvisited = UINT32_MAX; |
38 | | static constexpr uint32_t Visiting = UINT32_MAX - 1; |
39 | | |
40 | | // TODO: make the super type depth table instead of recursively querying. |
41 | | Expect<uint32_t> |
42 | | checkSubtypeDepth(const uint32_t BaseIdx, uint32_t TestIdx, uint32_t Depth, |
43 | | std::vector<uint32_t> &DepthMap, |
44 | 34 | const std::vector<const WasmEdge::AST::SubType *> &TypeVec) { |
45 | 34 | if (TestIdx >= DepthMap.size()) { |
46 | 0 | DepthMap.resize(TestIdx + 1, Unvisited); |
47 | 34 | } else if (DepthMap[TestIdx] == Visiting) { |
48 | 0 | spdlog::error(ErrCode::Value::InvalidSubType); |
49 | 0 | spdlog::error(" Cycle detected in subtype hierarchy for type {}."sv, |
50 | 0 | BaseIdx); |
51 | 0 | return Unexpect(ErrCode::Value::InvalidSubType); |
52 | 34 | } else if (DepthMap[TestIdx] != Unvisited) { |
53 | 1 | return DepthMap[TestIdx]; |
54 | 1 | } |
55 | | |
56 | 33 | if (Depth >= MaxSubtypeDepth) { |
57 | 0 | spdlog::error(ErrCode::Value::InvalidSubType); |
58 | 0 | spdlog::error(" Subtype depth for type {} exceeded the limits of {}"sv, |
59 | 0 | BaseIdx, MaxSubtypeDepth); |
60 | 0 | return Unexpect(ErrCode::Value::InvalidSubType); |
61 | 0 | } |
62 | | |
63 | 33 | DepthMap[TestIdx] = Visiting; |
64 | 33 | uint32_t MaxDepth = 0; |
65 | 33 | const auto &TestType = *TypeVec[TestIdx]; |
66 | 33 | for (const auto SuperIdx : TestType.getSuperTypeIndices()) { |
67 | 1 | if (unlikely(SuperIdx >= TypeVec.size())) { |
68 | 0 | spdlog::error(ErrCode::Value::InvalidSubType); |
69 | 0 | spdlog::error(ErrInfo::InfoForbidIndex( |
70 | 0 | ErrInfo::IndexCategory::DefinedType, SuperIdx, |
71 | 0 | static_cast<uint32_t>(TypeVec.size()))); |
72 | 0 | return Unexpect(ErrCode::Value::InvalidSubType); |
73 | 0 | } |
74 | 2 | EXPECTED_TRY( |
75 | 2 | auto RetDepth, |
76 | 2 | checkSubtypeDepth(BaseIdx, SuperIdx, Depth + 1, DepthMap, TypeVec) |
77 | 2 | .map_error([=](auto E) { |
78 | 2 | spdlog::error( |
79 | 2 | " When checking subtype hierarchy of super type {}."sv, |
80 | 2 | SuperIdx); |
81 | 2 | return E; |
82 | 2 | })); |
83 | 2 | MaxDepth = std::max(MaxDepth, RetDepth + 1); |
84 | 2 | } |
85 | | |
86 | 33 | if (MaxDepth >= MaxSubtypeDepth) { |
87 | 0 | spdlog::error(ErrCode::Value::InvalidSubType); |
88 | 0 | spdlog::error(" Subtype depth for type {} exceeded the limits of {}"sv, |
89 | 0 | BaseIdx, MaxSubtypeDepth); |
90 | 0 | return Unexpect(ErrCode::Value::InvalidSubType); |
91 | 0 | } |
92 | | |
93 | 33 | DepthMap[TestIdx] = MaxDepth; |
94 | 33 | return MaxDepth; |
95 | 33 | } |
96 | | |
97 | | } // namespace |
98 | | |
99 | | // Validator constructor. See "include/validator/validator.h". |
100 | | Validator::Validator(const Configure &Conf) noexcept |
101 | 9.70k | : Conf(Conf), |
102 | 9.70k | CoreFuncType_I32_I32(makeCoreFuncType({TypeCode::I32}, {TypeCode::I32})), |
103 | 9.70k | CoreFuncType_I32_Void(makeCoreFuncType({TypeCode::I32}, {})) {} |
104 | | |
105 | | // Validate Module. See "include/validator/validator.h". |
106 | 6.72k | Expect<void> Validator::validate(const AST::Module &Mod) { |
107 | | // https://webassembly.github.io/spec/core/valid/modules.html |
108 | 6.72k | Checker.reset(true); |
109 | | |
110 | | // Validate and register type section. |
111 | 6.72k | EXPECTED_TRY(validate(Mod.getTypeSection()).map_error([](auto E) { |
112 | 6.66k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type)); |
113 | 6.66k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
114 | 6.66k | return E; |
115 | 6.66k | })); |
116 | | |
117 | | // Validate and register the import section in FormChecker. |
118 | 6.66k | EXPECTED_TRY(validate(Mod.getImportSection()).map_error([](auto E) { |
119 | 6.60k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Import)); |
120 | 6.60k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
121 | 6.60k | return E; |
122 | 6.60k | })); |
123 | | |
124 | | // Validate the function section and register functions in FormChecker. |
125 | 6.60k | EXPECTED_TRY(validate(Mod.getFunctionSection()).map_error([](auto E) { |
126 | 6.58k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Function)); |
127 | 6.58k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
128 | 6.58k | return E; |
129 | 6.58k | })); |
130 | | |
131 | | // Validate the table section and register tables in FormChecker. |
132 | 6.58k | EXPECTED_TRY(validate(Mod.getTableSection()).map_error([](auto E) { |
133 | 6.40k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Table)); |
134 | 6.40k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
135 | 6.40k | return E; |
136 | 6.40k | })); |
137 | | |
138 | | // Validate the memory section and register memories in FormChecker. |
139 | 6.40k | EXPECTED_TRY(validate(Mod.getMemorySection()).map_error([](auto E) { |
140 | 6.16k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Memory)); |
141 | 6.16k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
142 | 6.16k | return E; |
143 | 6.16k | })); |
144 | | |
145 | | // Validate the global section and register globals in FormChecker. |
146 | 6.16k | EXPECTED_TRY(validate(Mod.getGlobalSection()).map_error([](auto E) { |
147 | 5.80k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Global)); |
148 | 5.80k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
149 | 5.80k | return E; |
150 | 5.80k | })); |
151 | | |
152 | | // Validate the tag section and register tags in FormChecker. |
153 | 5.80k | EXPECTED_TRY(validate(Mod.getTagSection()).map_error([](auto E) { |
154 | 5.75k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Tag)); |
155 | 5.75k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
156 | 5.75k | return E; |
157 | 5.75k | })); |
158 | | |
159 | | // Validate export section. |
160 | 5.75k | EXPECTED_TRY(validate(Mod.getExportSection()).map_error([](auto E) { |
161 | 5.58k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Export)); |
162 | 5.58k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
163 | 5.58k | return E; |
164 | 5.58k | })); |
165 | | |
166 | | // Validate start section. |
167 | 5.58k | EXPECTED_TRY(validate(Mod.getStartSection()).map_error([](auto E) { |
168 | 5.53k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Start)); |
169 | 5.53k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
170 | 5.53k | return E; |
171 | 5.53k | })); |
172 | | |
173 | | // Validate the element section that initializes tables. |
174 | 5.53k | EXPECTED_TRY(validate(Mod.getElementSection()).map_error([](auto E) { |
175 | 5.42k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Element)); |
176 | 5.42k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
177 | 5.42k | return E; |
178 | 5.42k | })); |
179 | | |
180 | | // Validate the data section that initializes memories. |
181 | 5.42k | EXPECTED_TRY(validate(Mod.getDataSection()).map_error([](auto E) { |
182 | 5.40k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Data)); |
183 | 5.40k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
184 | 5.40k | return E; |
185 | 5.40k | })); |
186 | | |
187 | | // Validate code section and expressions. |
188 | 5.40k | EXPECTED_TRY(validate(Mod.getCodeSection()).map_error([](auto E) { |
189 | 3.86k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Code)); |
190 | 3.86k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
191 | 3.86k | return E; |
192 | 3.86k | })); |
193 | | |
194 | | // Multiple tables are for the ReferenceTypes proposal. |
195 | 3.86k | if (Checker.getTables().size() > 1 && |
196 | 62 | !Conf.hasProposal(Proposal::ReferenceTypes)) { |
197 | 0 | spdlog::error(ErrCode::Value::MultiTables); |
198 | 0 | spdlog::error(ErrInfo::InfoProposal(Proposal::ReferenceTypes)); |
199 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
200 | 0 | return Unexpect(ErrCode::Value::MultiTables); |
201 | 0 | } |
202 | | |
203 | | // Multiple memories are for the MultiMemories proposal. |
204 | 3.86k | if (Checker.getMemories().size() > 1 && |
205 | 77 | !Conf.hasProposal(Proposal::MultiMemories)) { |
206 | 0 | spdlog::error(ErrCode::Value::MultiMemories); |
207 | 0 | spdlog::error(ErrInfo::InfoProposal(Proposal::MultiMemories)); |
208 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
209 | 0 | return Unexpect(ErrCode::Value::MultiMemories); |
210 | 0 | } |
211 | | |
212 | | // Set the validated flag. |
213 | 3.86k | const_cast<AST::Module &>(Mod).setIsValidated(); |
214 | 3.86k | return {}; |
215 | 3.86k | } |
216 | | |
217 | | // Validate Sub type. See "include/validator/validator.h". |
218 | | Expect<void> Validator::validate(const AST::SubType &Type, uint32_t OwnTypeIdx, |
219 | 8.60k | std::vector<uint32_t> &SubTypeDepthMap) { |
220 | 8.60k | const auto &TypeVec = Checker.getTypes(); |
221 | 8.60k | const auto &CompType = Type.getCompositeType(); |
222 | | |
223 | | // Check the validation of the composite type. |
224 | 8.60k | if (CompType.isFunc()) { |
225 | 8.13k | const auto &FType = CompType.getFuncType(); |
226 | 8.13k | for (auto &PType : FType.getParamTypes()) { |
227 | 6.74k | EXPECTED_TRY(Checker.validate(PType).map_error([](auto E) { |
228 | 6.74k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function)); |
229 | 6.74k | return E; |
230 | 6.74k | })); |
231 | 6.74k | } |
232 | 8.12k | if (unlikely(!Conf.hasProposal(Proposal::MultiValue)) && |
233 | 0 | FType.getReturnTypes().size() > 1) { |
234 | 0 | spdlog::error(ErrCode::Value::InvalidResultArity); |
235 | 0 | spdlog::error(ErrInfo::InfoProposal(Proposal::MultiValue)); |
236 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function)); |
237 | 0 | return Unexpect(ErrCode::Value::InvalidResultArity); |
238 | 0 | } |
239 | 8.12k | for (auto &RType : FType.getReturnTypes()) { |
240 | 5.99k | EXPECTED_TRY(Checker.validate(RType).map_error([](auto E) { |
241 | 5.99k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function)); |
242 | 5.99k | return E; |
243 | 5.99k | })); |
244 | 5.99k | } |
245 | 8.12k | } else { |
246 | 473 | const auto &FTypes = CompType.getFieldTypes(); |
247 | 473 | for (auto &FieldType : FTypes) { |
248 | 302 | EXPECTED_TRY(Checker.validate(FieldType.getStorageType())); |
249 | 302 | } |
250 | 473 | } |
251 | | |
252 | | // In the current version, the length of the type index vector will be <= 1. |
253 | 8.58k | if (Type.getSuperTypeIndices().size() > 1) { |
254 | 2 | spdlog::error(ErrCode::Value::InvalidSubType); |
255 | 2 | spdlog::error(" Accepts only one super type currently."sv); |
256 | 2 | return Unexpect(ErrCode::Value::InvalidSubType); |
257 | 2 | } |
258 | | |
259 | 8.57k | for (const auto &Index : Type.getSuperTypeIndices()) { |
260 | | // A super type must be previously defined (smaller index than this sub |
261 | | // type), so OwnTypeIdx is the exclusive bound, subsuming the range check. |
262 | 41 | if (unlikely(Index >= OwnTypeIdx)) { |
263 | 8 | spdlog::error(ErrCode::Value::InvalidSubType); |
264 | 8 | spdlog::error(" Super type index {} must be smaller than the sub type " |
265 | 8 | "index {}."sv, |
266 | 8 | Index, OwnTypeIdx); |
267 | 8 | return Unexpect(ErrCode::Value::InvalidSubType); |
268 | 8 | } |
269 | | |
270 | 33 | EXPECTED_TRY( |
271 | 33 | checkSubtypeDepth(Index, Index, 0, SubTypeDepthMap, TypeVec) |
272 | 33 | .map_error([=](auto E) { |
273 | 33 | spdlog::error( |
274 | 33 | " When checking subtype hierarchy of super type {}."sv, |
275 | 33 | Index); |
276 | 33 | return E; |
277 | 33 | })); |
278 | | |
279 | 33 | if (TypeVec[Index]->isFinal()) { |
280 | 1 | spdlog::error(ErrCode::Value::InvalidSubType); |
281 | 1 | spdlog::error(" Super type should not be final."sv); |
282 | 1 | return Unexpect(ErrCode::Value::InvalidSubType); |
283 | 1 | } |
284 | 32 | auto &SuperType = TypeVec[Index]->getCompositeType(); |
285 | 32 | if (!AST::TypeMatcher::matchType(Checker.getTypes(), SuperType, CompType)) { |
286 | 23 | spdlog::error(ErrCode::Value::InvalidSubType); |
287 | 23 | spdlog::error(" Super type not matched."sv); |
288 | 23 | return Unexpect(ErrCode::Value::InvalidSubType); |
289 | 23 | } |
290 | 32 | } |
291 | 8.54k | return {}; |
292 | 8.57k | } |
293 | | |
294 | | // Validate Limit type. See "include/validator/validator.h". |
295 | 3.31k | Expect<void> Validator::validate(const AST::Limit &Lim) { |
296 | 3.31k | if (Lim.hasMax() && Lim.getMin() > Lim.getMax()) { |
297 | 86 | spdlog::error(ErrCode::Value::InvalidLimit); |
298 | 86 | spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax())); |
299 | 86 | return Unexpect(ErrCode::Value::InvalidLimit); |
300 | 86 | } |
301 | 3.22k | if (Lim.isShared() && unlikely(!Lim.hasMax())) { |
302 | 0 | spdlog::error(ErrCode::Value::SharedMemoryNoMax); |
303 | 0 | return Unexpect(ErrCode::Value::SharedMemoryNoMax); |
304 | 0 | } |
305 | 3.22k | return {}; |
306 | 3.22k | } |
307 | | |
308 | | // Validate Table type. See "include/validator/validator.h". |
309 | 1.09k | Expect<void> Validator::validate(const AST::TableType &Tab) { |
310 | | // Validate value type. |
311 | 1.09k | EXPECTED_TRY(Checker.validate(Tab.getRefType())); |
312 | | // Validate table limits. |
313 | 1.06k | const auto &Lim = Tab.getLimit(); |
314 | 1.06k | EXPECTED_TRY(validate(Lim).map_error([](auto E) { |
315 | 1.03k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit)); |
316 | 1.03k | return E; |
317 | 1.03k | })); |
318 | 1.03k | uint64_t Range = getMaxAddress(Lim.getAddrType()); |
319 | 1.03k | if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) { |
320 | | // Since spec test has no related error message, use this error instead. |
321 | 122 | auto Code = Conf.hasProposal(Proposal::Memory64) |
322 | 122 | ? ErrCode::Value::InvalidTableSize64 |
323 | 122 | : ErrCode::Value::InvalidLimit; |
324 | 122 | spdlog::error(Code); |
325 | 122 | spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax())); |
326 | 122 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit)); |
327 | 122 | return Unexpect(Code); |
328 | 122 | } |
329 | 909 | return {}; |
330 | 1.03k | } |
331 | | |
332 | | // Validate Memory type. See "include/validator/validator.h". |
333 | 2.24k | Expect<void> Validator::validate(const AST::MemoryType &Mem) { |
334 | | // Validate memory limits. |
335 | 2.24k | const auto &Lim = Mem.getLimit(); |
336 | 2.24k | EXPECTED_TRY(validate(Lim).map_error([](auto E) { |
337 | 2.19k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit)); |
338 | 2.19k | return E; |
339 | 2.19k | })); |
340 | 2.19k | if (!Conf.hasProposal(Proposal::Memory64) && Lim.is64()) { |
341 | 0 | spdlog::error(ErrCode::Value::InvalidLimit); |
342 | 0 | spdlog::error(ErrInfo::InfoProposal(Proposal::Memory64)); |
343 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit)); |
344 | 0 | return Unexpect(ErrCode::Value::InvalidLimit); |
345 | 0 | } |
346 | 2.19k | uint64_t Range = Lim.is32() ? (static_cast<uint64_t>(1) << 16) |
347 | 2.19k | : (static_cast<uint64_t>(1) << 48); |
348 | 2.19k | if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) { |
349 | 186 | auto Code = Conf.hasProposal(Proposal::Memory64) |
350 | 186 | ? ErrCode::Value::InvalidMemPages64 |
351 | 186 | : ErrCode::Value::InvalidMemPages; |
352 | 186 | spdlog::error(Code); |
353 | 186 | spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax())); |
354 | 186 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit)); |
355 | 186 | return Unexpect(Code); |
356 | 186 | } |
357 | 2.00k | return {}; |
358 | 2.19k | } |
359 | | |
360 | | // Validate Global type. See "include/validator/validator.h". |
361 | 405 | Expect<void> Validator::validate(const AST::GlobalType &Glob) { |
362 | | // Validate value type. |
363 | 405 | return Checker.validate(Glob.getValType()); |
364 | 405 | } |
365 | | |
366 | | // Validate Table segment. See "include/validator/validator.h". |
367 | 988 | Expect<void> Validator::validate(const AST::TableSegment &TabSeg) { |
368 | 988 | if (TabSeg.getExpr().getInstrs().size() > 0) { |
369 | | // Check ref initialization is a const expression. |
370 | 8 | EXPECTED_TRY( |
371 | 8 | validateConstExpr(TabSeg.getExpr().getInstrs(), |
372 | 8 | {ValType(TabSeg.getTableType().getRefType())}) |
373 | 8 | .map_error([](auto E) { |
374 | 8 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression)); |
375 | 8 | return E; |
376 | 8 | })); |
377 | 980 | } else { |
378 | | // No init expression. Check that the reference type is nullable. |
379 | 980 | if (!TabSeg.getTableType().getRefType().isNullableRefType()) { |
380 | 4 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
381 | 4 | spdlog::error(ErrInfo::InfoMismatch( |
382 | 4 | ValType(TypeCode::RefNull, |
383 | 4 | TabSeg.getTableType().getRefType().getHeapTypeCode(), |
384 | 4 | TabSeg.getTableType().getRefType().getTypeIndex()), |
385 | 4 | TabSeg.getTableType().getRefType())); |
386 | 4 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
387 | 4 | } |
388 | 980 | } |
389 | | // Validate table type. |
390 | 980 | return validate(TabSeg.getTableType()).map_error([](auto E) { |
391 | 180 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table)); |
392 | 180 | return E; |
393 | 180 | }); |
394 | 988 | } |
395 | | |
396 | | // Validate Global segment. See "include/validator/validator.h". |
397 | 669 | Expect<void> Validator::validate(const AST::GlobalSegment &GlobSeg) { |
398 | | // Check global initialization is a const expression. |
399 | 669 | EXPECTED_TRY(validateConstExpr(GlobSeg.getExpr().getInstrs(), |
400 | 315 | {GlobSeg.getGlobalType().getValType()}) |
401 | 315 | .map_error([](auto E) { |
402 | 315 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression)); |
403 | 315 | return E; |
404 | 315 | })); |
405 | | // Validate global type. |
406 | 315 | return validate(GlobSeg.getGlobalType()).map_error([](auto E) { |
407 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global)); |
408 | 0 | return E; |
409 | 0 | }); |
410 | 669 | } |
411 | | |
412 | | // Validate Element segment. See "include/validator/validator.h". |
413 | 605 | Expect<void> Validator::validate(const AST::ElementSegment &ElemSeg) { |
414 | | // Check that initialization expressions are const expressions. |
415 | 1.45k | for (auto &Expr : ElemSeg.getInitExprs()) { |
416 | 1.45k | EXPECTED_TRY( |
417 | 1.45k | validateConstExpr(Expr.getInstrs(), {ValType(ElemSeg.getRefType())}) |
418 | 1.45k | .map_error([](auto E) { |
419 | 1.45k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression)); |
420 | 1.45k | return E; |
421 | 1.45k | })); |
422 | 1.45k | } |
423 | | |
424 | | // The reference type should be valid. |
425 | 547 | EXPECTED_TRY(Checker.validate(ElemSeg.getRefType())); |
426 | | |
427 | | // Passive and declarative cases are valid with a valid reference type. |
428 | 545 | if (ElemSeg.getMode() == AST::ElementSegment::ElemMode::Active) { |
429 | | // Check table index and reference type in context. |
430 | 312 | const auto &TableVec = Checker.getTables(); |
431 | 312 | if (ElemSeg.getIdx() >= TableVec.size()) { |
432 | 36 | spdlog::error(ErrCode::Value::InvalidTableIdx); |
433 | 36 | spdlog::error(ErrInfo::InfoForbidIndex( |
434 | 36 | ErrInfo::IndexCategory::Table, ElemSeg.getIdx(), |
435 | 36 | static_cast<uint32_t>(TableVec.size()))); |
436 | 36 | return Unexpect(ErrCode::Value::InvalidTableIdx); |
437 | 36 | } |
438 | 276 | if (!AST::TypeMatcher::matchType(Checker.getTypes(), |
439 | 276 | TableVec[ElemSeg.getIdx()].second, |
440 | 276 | ElemSeg.getRefType())) { |
441 | | // Reference type does not match. |
442 | 7 | spdlog::error(ErrCode::Value::TypeCheckFailed); |
443 | 7 | spdlog::error(ErrInfo::InfoMismatch(TableVec[ElemSeg.getIdx()].second, |
444 | 7 | ElemSeg.getRefType())); |
445 | 7 | return Unexpect(ErrCode::Value::TypeCheckFailed); |
446 | 7 | } |
447 | | // Check table initialization is a const expression. |
448 | 269 | return validateConstExpr(ElemSeg.getExpr().getInstrs(), |
449 | 269 | {ValType(TableVec[ElemSeg.getIdx()].first)}) |
450 | 269 | .map_error([](auto E) { |
451 | 4 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression)); |
452 | 4 | return E; |
453 | 4 | }); |
454 | 276 | } |
455 | 233 | return {}; |
456 | 545 | } |
457 | | |
458 | | // Validate Code segment. See "include/validator/validator.h". |
459 | | Expect<void> Validator::validate(const AST::CodeSegment &CodeSeg, |
460 | 12.8k | const uint32_t TypeIdx) { |
461 | | // Due to validation of the function section, the type at this index must |
462 | | // be a function type. |
463 | 12.8k | const auto &FuncType = |
464 | 12.8k | Checker.getTypes()[TypeIdx]->getCompositeType().getFuncType(); |
465 | | // Reset stack in FormChecker. |
466 | 12.8k | Checker.reset(); |
467 | | // Add parameters to this frame. |
468 | 12.8k | for (auto &Type : FuncType.getParamTypes()) { |
469 | | // Local passed by function parameters must have been initialized. |
470 | 10.4k | Checker.addLocal(Type, true); |
471 | 10.4k | } |
472 | | // Add locals to this frame. |
473 | 12.8k | for (auto Val : CodeSeg.getLocals()) { |
474 | 132M | for (uint32_t Cnt = 0; Cnt < Val.first; ++Cnt) { |
475 | | // The local value type should be valid. |
476 | 132M | EXPECTED_TRY(Checker.validate(Val.second)); |
477 | 132M | Checker.addLocal(Val.second, false); |
478 | 132M | } |
479 | 2.20k | } |
480 | | // Validate function body expression. |
481 | 12.8k | return Checker |
482 | 12.8k | .validate(CodeSeg.getExpr().getInstrs(), FuncType.getReturnTypes()) |
483 | 12.8k | .map_error([](auto E) { |
484 | 1.53k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression)); |
485 | 1.53k | return E; |
486 | 1.53k | }); |
487 | 12.8k | } |
488 | | |
489 | | // Validate Data segment. See "include/validator/validator.h". |
490 | 1.09k | Expect<void> Validator::validate(const AST::DataSegment &DataSeg) { |
491 | 1.09k | switch (DataSeg.getMode()) { |
492 | 209 | case AST::DataSegment::DataMode::Active: { |
493 | | // Check memory index in context. |
494 | 209 | const auto &MemVec = Checker.getMemories(); |
495 | 209 | if (DataSeg.getIdx() >= MemVec.size()) { |
496 | 19 | spdlog::error(ErrCode::Value::InvalidMemoryIdx); |
497 | 19 | spdlog::error(ErrInfo::InfoForbidIndex( |
498 | 19 | ErrInfo::IndexCategory::Memory, DataSeg.getIdx(), |
499 | 19 | static_cast<uint32_t>(MemVec.size()))); |
500 | 19 | return Unexpect(ErrCode::Value::InvalidMemoryIdx); |
501 | 19 | } |
502 | | // Check memory initialization is a const expression. |
503 | 190 | return validateConstExpr(DataSeg.getExpr().getInstrs(), |
504 | 190 | {ValType(MemVec[DataSeg.getIdx()])}) |
505 | 190 | .map_error([](auto E) { |
506 | 6 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression)); |
507 | 6 | return E; |
508 | 6 | }); |
509 | 209 | } |
510 | 888 | case AST::DataSegment::DataMode::Passive: |
511 | | // Passive case is always valid. |
512 | 888 | return {}; |
513 | 0 | default: |
514 | 0 | return {}; |
515 | 1.09k | } |
516 | 1.09k | } |
517 | | |
518 | | // Validate Import description. See "include/validator/validator.h". |
519 | 1.29k | Expect<void> Validator::validate(const AST::ImportDesc &ImpDesc) { |
520 | 1.29k | switch (ImpDesc.getExternalType()) { |
521 | | // External type and external content are ensured to match in the loader |
522 | | // phase. |
523 | 741 | case ExternalType::Function: { |
524 | 741 | const auto TId = ImpDesc.getExternalFuncTypeIdx(); |
525 | | // Function type index must exist in context and be valid. |
526 | 741 | if (TId >= Checker.getTypes().size()) { |
527 | 21 | spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); |
528 | 21 | spdlog::error(ErrInfo::InfoForbidIndex( |
529 | 21 | ErrInfo::IndexCategory::FunctionType, TId, |
530 | 21 | static_cast<uint32_t>(Checker.getTypes().size()))); |
531 | 21 | return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); |
532 | 21 | } |
533 | 720 | if (!Checker.getTypes()[TId]->getCompositeType().isFunc()) { |
534 | 3 | spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); |
535 | 3 | spdlog::error(" Defined type index {} is not a function type."sv, TId); |
536 | 3 | return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); |
537 | 3 | } |
538 | 717 | Checker.addRef(static_cast<uint32_t>(Checker.getFunctions().size())); |
539 | 717 | Checker.addFunc(TId, true); |
540 | 717 | return {}; |
541 | 720 | } |
542 | 114 | case ExternalType::Table: { |
543 | 114 | const auto &TabType = ImpDesc.getExternalTableType(); |
544 | | // Table type must be valid. |
545 | 114 | EXPECTED_TRY(validate(TabType).map_error([](auto E) { |
546 | 109 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table)); |
547 | 109 | return E; |
548 | 109 | })); |
549 | 109 | Checker.addTable(TabType); |
550 | 109 | return {}; |
551 | 114 | } |
552 | 188 | case ExternalType::Memory: { |
553 | 188 | const auto &MemType = ImpDesc.getExternalMemoryType(); |
554 | | // Memory type must be valid. |
555 | 188 | EXPECTED_TRY(validate(MemType).map_error([](auto E) { |
556 | 185 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory)); |
557 | 185 | return E; |
558 | 185 | })); |
559 | 185 | Checker.addMemory(MemType); |
560 | 185 | return {}; |
561 | 188 | } |
562 | 161 | case ExternalType::Tag: { |
563 | 161 | const auto &T = ImpDesc.getExternalTagType(); |
564 | | // Tag type index must exist in context. |
565 | 161 | auto TagTypeIdx = T.getTypeIdx(); |
566 | 161 | if (TagTypeIdx >= Checker.getTypes().size()) { |
567 | 22 | spdlog::error(ErrCode::Value::InvalidTagIdx); |
568 | 22 | spdlog::error(ErrInfo::InfoForbidIndex( |
569 | 22 | ErrInfo::IndexCategory::TagType, TagTypeIdx, |
570 | 22 | static_cast<uint32_t>(Checker.getTypes().size()))); |
571 | 22 | return Unexpect(ErrCode::Value::InvalidTagIdx); |
572 | 22 | } |
573 | | // Tag type must be valid. |
574 | 139 | auto &CompType = Checker.getTypes()[TagTypeIdx]->getCompositeType(); |
575 | 139 | if (!CompType.isFunc()) { |
576 | 2 | spdlog::error(ErrCode::Value::InvalidTagIdx); |
577 | 2 | spdlog::error(" Defined type index {} is not a function type."sv, |
578 | 2 | TagTypeIdx); |
579 | 2 | return Unexpect(ErrCode::Value::InvalidTagIdx); |
580 | 2 | } |
581 | 137 | if (!CompType.getFuncType().getReturnTypes().empty()) { |
582 | 2 | spdlog::error(ErrCode::Value::InvalidTagResultType); |
583 | 2 | return Unexpect(ErrCode::Value::InvalidTagResultType); |
584 | 2 | } |
585 | 135 | Checker.addTag(TagTypeIdx); |
586 | 135 | return {}; |
587 | 137 | } |
588 | 90 | case ExternalType::Global: { |
589 | 90 | const auto &GlobType = ImpDesc.getExternalGlobalType(); |
590 | | // Global type must be valid. |
591 | 90 | EXPECTED_TRY(validate(GlobType).map_error([](auto E) { |
592 | 86 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global)); |
593 | 86 | return E; |
594 | 86 | })); |
595 | 86 | Checker.addGlobal(GlobType, true); |
596 | 86 | return {}; |
597 | 90 | } |
598 | 0 | default: |
599 | 0 | return {}; |
600 | 1.29k | } |
601 | 1.29k | } |
602 | | |
603 | | // Validate Export description. See "include/validator/validator.h". |
604 | 11.2k | Expect<void> Validator::validate(const AST::ExportDesc &ExpDesc) { |
605 | 11.2k | auto Id = ExpDesc.getExternalIndex(); |
606 | 11.2k | switch (ExpDesc.getExternalType()) { |
607 | 10.8k | case ExternalType::Function: |
608 | 10.8k | if (Id >= Checker.getFunctions().size()) { |
609 | 43 | spdlog::error(ErrCode::Value::InvalidFuncIdx); |
610 | 43 | spdlog::error(ErrInfo::InfoForbidIndex( |
611 | 43 | ErrInfo::IndexCategory::Function, Id, |
612 | 43 | static_cast<uint32_t>(Checker.getFunctions().size()))); |
613 | 43 | return Unexpect(ErrCode::Value::InvalidFuncIdx); |
614 | 43 | } |
615 | 10.8k | Checker.addRef(Id); |
616 | 10.8k | return {}; |
617 | 67 | case ExternalType::Table: |
618 | 67 | if (Id >= Checker.getTables().size()) { |
619 | 39 | spdlog::error(ErrCode::Value::InvalidTableIdx); |
620 | 39 | spdlog::error(ErrInfo::InfoForbidIndex( |
621 | 39 | ErrInfo::IndexCategory::Table, Id, |
622 | 39 | static_cast<uint32_t>(Checker.getTables().size()))); |
623 | 39 | return Unexpect(ErrCode::Value::InvalidTableIdx); |
624 | 39 | } |
625 | 28 | return {}; |
626 | 148 | case ExternalType::Memory: |
627 | 148 | if (Id >= Checker.getMemories().size()) { |
628 | 45 | spdlog::error(ErrCode::Value::InvalidMemoryIdx); |
629 | 45 | spdlog::error(ErrInfo::InfoForbidIndex( |
630 | 45 | ErrInfo::IndexCategory::Memory, Id, |
631 | 45 | static_cast<uint32_t>(Checker.getMemories().size()))); |
632 | 45 | return Unexpect(ErrCode::Value::InvalidMemoryIdx); |
633 | 45 | } |
634 | 103 | return {}; |
635 | 35 | case ExternalType::Tag: |
636 | 35 | if (Id >= Checker.getTags().size()) { |
637 | 25 | spdlog::error(ErrCode::Value::InvalidTagIdx); |
638 | 25 | spdlog::error(ErrInfo::InfoForbidIndex( |
639 | 25 | ErrInfo::IndexCategory::Tag, Id, |
640 | 25 | static_cast<uint32_t>(Checker.getTags().size()))); |
641 | 25 | return Unexpect(ErrCode::Value::InvalidTagIdx); |
642 | 25 | } |
643 | 10 | return {}; |
644 | 135 | case ExternalType::Global: |
645 | 135 | if (Id >= Checker.getGlobals().size()) { |
646 | 14 | spdlog::error(ErrCode::Value::InvalidGlobalIdx); |
647 | 14 | spdlog::error(ErrInfo::InfoForbidIndex( |
648 | 14 | ErrInfo::IndexCategory::Global, Id, |
649 | 14 | static_cast<uint32_t>(Checker.getGlobals().size()))); |
650 | 14 | return Unexpect(ErrCode::Value::InvalidGlobalIdx); |
651 | 14 | } |
652 | 121 | return {}; |
653 | 0 | default: |
654 | 0 | return {}; |
655 | 11.2k | } |
656 | 11.2k | } |
657 | | |
658 | 6.72k | Expect<void> Validator::validate(const AST::TypeSection &TypeSec) { |
659 | 6.72k | const auto STypeList = TypeSec.getContent(); |
660 | 6.72k | std::vector<uint32_t> SubTypeDepthMap(STypeList.size(), Unvisited); |
661 | 6.72k | uint32_t Idx = 0; |
662 | 15.2k | while (Idx < STypeList.size()) { |
663 | 8.57k | const auto &SType = STypeList[Idx]; |
664 | | // The next type to add takes this index in the type index space. |
665 | 8.57k | const uint32_t BaseIdx = static_cast<uint32_t>(Checker.getTypes().size()); |
666 | 8.57k | if (Conf.hasProposal(Proposal::GC)) { |
667 | | // With GC a type is (self-)recursive (a singleton is a rec group of 1): |
668 | | // add the whole group before validating so members can reference it. |
669 | 8.57k | const uint32_t RecSize = SType.getRecursiveInfo().has_value() |
670 | 8.57k | ? SType.getRecursiveInfo()->RecTypeSize |
671 | 8.57k | : 1; |
672 | 17.1k | for (uint32_t I = Idx; I < Idx + RecSize; I++) { |
673 | 8.62k | Checker.addType(STypeList[I]); |
674 | 8.62k | } |
675 | 17.1k | for (uint32_t I = Idx; I < Idx + RecSize; I++) { |
676 | 8.60k | EXPECTED_TRY( |
677 | 8.60k | validate(STypeList[I], BaseIdx + (I - Idx), SubTypeDepthMap) |
678 | 8.60k | .map_error([](auto E) { |
679 | 8.60k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Rec)); |
680 | 8.60k | return E; |
681 | 8.60k | })); |
682 | 8.60k | } |
683 | 8.51k | Idx += RecSize; |
684 | 8.51k | } else { |
685 | | // Without GC there are no rec groups: a type may reference only earlier |
686 | | // ones, so validate it before registering. |
687 | 0 | EXPECTED_TRY(validate(SType, BaseIdx, SubTypeDepthMap)); |
688 | 0 | Checker.addType(SType); |
689 | 0 | Idx++; |
690 | 0 | } |
691 | 8.57k | } |
692 | 6.66k | return {}; |
693 | 6.72k | } |
694 | | |
695 | | // Validate Import section. See "include/validator/validator.h". |
696 | 6.66k | Expect<void> Validator::validate(const AST::ImportSection &ImportSec) { |
697 | 6.66k | for (auto &ImportDesc : ImportSec.getContent()) { |
698 | 1.29k | EXPECTED_TRY(validate(ImportDesc).map_error([](auto E) { |
699 | 1.29k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Import)); |
700 | 1.29k | return E; |
701 | 1.29k | })); |
702 | 1.29k | } |
703 | 6.60k | return {}; |
704 | 6.66k | } |
705 | | |
706 | | // Validate Function section. See "include/validator/validator.h". |
707 | 6.60k | Expect<void> Validator::validate(const AST::FunctionSection &FuncSec) { |
708 | 6.60k | const auto &FuncVec = FuncSec.getContent(); |
709 | 6.60k | const auto &TypeVec = Checker.getTypes(); |
710 | | |
711 | | // Check whether the function type ID is valid in context. |
712 | 18.8k | for (auto &TId : FuncVec) { |
713 | 18.8k | if (TId >= TypeVec.size()) { |
714 | 16 | spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); |
715 | 16 | spdlog::error( |
716 | 16 | ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::FunctionType, TId, |
717 | 16 | static_cast<uint32_t>(TypeVec.size()))); |
718 | 16 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function)); |
719 | 16 | return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); |
720 | 16 | } |
721 | 18.8k | if (!TypeVec[TId]->getCompositeType().isFunc()) { |
722 | 1 | spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); |
723 | 1 | spdlog::error(" Defined type index {} is not a function type."sv, TId); |
724 | 1 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function)); |
725 | 1 | return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); |
726 | 1 | } |
727 | 18.8k | Checker.addFunc(TId); |
728 | 18.8k | } |
729 | 6.58k | return {}; |
730 | 6.60k | } |
731 | | |
732 | | // Validate Table section. See "include/validator/validator.h". |
733 | 6.58k | Expect<void> Validator::validate(const AST::TableSection &TabSec) { |
734 | 6.58k | for (auto &Tab : TabSec.getContent()) { |
735 | 988 | EXPECTED_TRY(validate(Tab).map_error([](auto E) { |
736 | 800 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); |
737 | 800 | return E; |
738 | 800 | })); |
739 | 800 | Checker.addTable(Tab.getTableType()); |
740 | 800 | } |
741 | 6.40k | return {}; |
742 | 6.58k | } |
743 | | |
744 | | // Validate Memory section. See "include/validator/validator.h". |
745 | 6.40k | Expect<void> Validator::validate(const AST::MemorySection &MemSec) { |
746 | 6.40k | for (auto &Mem : MemSec.getContent()) { |
747 | 2.06k | EXPECTED_TRY(validate(Mem).map_error([](auto E) { |
748 | 1.82k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory)); |
749 | 1.82k | return E; |
750 | 1.82k | })); |
751 | 1.82k | Checker.addMemory(Mem); |
752 | 1.82k | } |
753 | 6.16k | return {}; |
754 | 6.40k | } |
755 | | |
756 | | // Validate Global section. See "include/validator/validator.h". |
757 | 6.16k | Expect<void> Validator::validate(const AST::GlobalSection &GlobSec) { |
758 | 6.16k | for (auto &GlobSeg : GlobSec.getContent()) { |
759 | 669 | EXPECTED_TRY(validate(GlobSeg).map_error([](auto E) { |
760 | 315 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global)); |
761 | 315 | return E; |
762 | 315 | })); |
763 | 315 | Checker.addGlobal(GlobSeg.getGlobalType()); |
764 | 315 | } |
765 | 5.80k | return {}; |
766 | 6.16k | } |
767 | | |
768 | | // Validate Element section. See "include/validator/validator.h". |
769 | 5.53k | Expect<void> Validator::validate(const AST::ElementSection &ElemSec) { |
770 | 5.53k | for (auto &ElemSeg : ElemSec.getContent()) { |
771 | 605 | EXPECTED_TRY(validate(ElemSeg).map_error([](auto E) { |
772 | 498 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); |
773 | 498 | return E; |
774 | 498 | })); |
775 | 498 | Checker.addElem(ElemSeg); |
776 | 498 | } |
777 | 5.42k | return {}; |
778 | 5.53k | } |
779 | | |
780 | | // Validate Code section. See "include/validator/validator.h". |
781 | 5.40k | Expect<void> Validator::validate(const AST::CodeSection &CodeSec) { |
782 | 5.40k | const auto &CodeVec = CodeSec.getContent(); |
783 | 5.40k | const auto &FuncVec = Checker.getFunctions(); |
784 | | |
785 | | // Validate function body. |
786 | 16.7k | for (uint32_t Id = 0; Id < static_cast<uint32_t>(CodeVec.size()); ++Id) { |
787 | | // Added functions contain imported functions. |
788 | 12.8k | uint32_t TId = Id + static_cast<uint32_t>(Checker.getNumImportFuncs()); |
789 | 12.8k | if (TId >= static_cast<uint32_t>(FuncVec.size())) { |
790 | 0 | spdlog::error(ErrCode::Value::InvalidFuncIdx); |
791 | 0 | spdlog::error( |
792 | 0 | ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Function, TId, |
793 | 0 | static_cast<uint32_t>(FuncVec.size()))); |
794 | 0 | return Unexpect(ErrCode::Value::InvalidFuncIdx); |
795 | 0 | } |
796 | 12.8k | EXPECTED_TRY(validate(CodeVec[Id], FuncVec[TId]).map_error([](auto E) { |
797 | 12.8k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code)); |
798 | 12.8k | return E; |
799 | 12.8k | })); |
800 | 12.8k | } |
801 | 3.86k | return {}; |
802 | 5.40k | } |
803 | | |
804 | | // Validate Data section. See "include/validator/validator.h". |
805 | 5.42k | Expect<void> Validator::validate(const AST::DataSection &DataSec) { |
806 | 5.42k | for (auto &DataSeg : DataSec.getContent()) { |
807 | 1.09k | EXPECTED_TRY(validate(DataSeg).map_error([](auto E) { |
808 | 1.07k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data)); |
809 | 1.07k | return E; |
810 | 1.07k | })); |
811 | 1.07k | Checker.addData(DataSeg); |
812 | 1.07k | } |
813 | 5.40k | return {}; |
814 | 5.42k | } |
815 | | |
816 | | // Validate Start section. See "include/validator/validator.h". |
817 | 5.58k | Expect<void> Validator::validate(const AST::StartSection &StartSec) { |
818 | 5.58k | if (StartSec.getContent()) { |
819 | 54 | auto FId = *StartSec.getContent(); |
820 | 54 | if (FId >= Checker.getFunctions().size()) { |
821 | 43 | spdlog::error(ErrCode::Value::InvalidFuncIdx); |
822 | 43 | spdlog::error(ErrInfo::InfoForbidIndex( |
823 | 43 | ErrInfo::IndexCategory::Function, FId, |
824 | 43 | static_cast<uint32_t>(Checker.getFunctions().size()))); |
825 | 43 | return Unexpect(ErrCode::Value::InvalidFuncIdx); |
826 | 43 | } |
827 | 11 | auto TId = Checker.getFunctions()[FId]; |
828 | 11 | assuming(TId < Checker.getTypes().size()); |
829 | 11 | if (!Checker.getTypes()[TId]->getCompositeType().isFunc()) { |
830 | 0 | spdlog::error(ErrCode::Value::InvalidStartFunc); |
831 | 0 | spdlog::error(" Defined type index {} is not a function type."sv, TId); |
832 | 0 | return Unexpect(ErrCode::Value::InvalidStartFunc); |
833 | 0 | } |
834 | 11 | auto &Type = Checker.getTypes()[TId]->getCompositeType().getFuncType(); |
835 | 11 | if (Type.getParamTypes().size() != 0 || Type.getReturnTypes().size() != 0) { |
836 | | // Start function signature should be {}->{} |
837 | 5 | spdlog::error(ErrCode::Value::InvalidStartFunc); |
838 | 5 | spdlog::error(ErrInfo::InfoMismatch({}, {}, Type.getParamTypes(), |
839 | 5 | Type.getReturnTypes())); |
840 | 5 | return Unexpect(ErrCode::Value::InvalidStartFunc); |
841 | 5 | } |
842 | 11 | } |
843 | 5.53k | return {}; |
844 | 5.58k | } |
845 | | |
846 | | // Validate Export section. See "include/validator/validator.h". |
847 | 5.75k | Expect<void> Validator::validate(const AST::ExportSection &ExportSec) { |
848 | 5.75k | std::unordered_set<std::string_view, Hash::Hash> ExportNames; |
849 | 11.2k | for (auto &ExportDesc : ExportSec.getContent()) { |
850 | 11.2k | auto Result = ExportNames.emplace(ExportDesc.getExternalName()); |
851 | 11.2k | if (!Result.second) { |
852 | | // Duplicated export name. |
853 | 8 | spdlog::error(ErrCode::Value::DupExportName); |
854 | 8 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export)); |
855 | 8 | return Unexpect(ErrCode::Value::DupExportName); |
856 | 8 | } |
857 | 11.2k | EXPECTED_TRY(validate(ExportDesc).map_error([](auto E) { |
858 | 11.2k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export)); |
859 | 11.2k | return E; |
860 | 11.2k | })); |
861 | 11.2k | } |
862 | 5.58k | return {}; |
863 | 5.75k | } |
864 | | |
865 | | // Validate Tag section. See "include/validator/validator.h". |
866 | 5.80k | Expect<void> Validator::validate(const AST::TagSection &TagSec) { |
867 | 5.80k | const auto &TagVec = TagSec.getContent(); |
868 | 5.80k | const auto &TypeVec = Checker.getTypes(); |
869 | | |
870 | | // Check whether the tag type ID is valid in context. |
871 | 5.80k | for (auto &TagType : TagVec) { |
872 | 207 | auto TagTypeIdx = TagType.getTypeIdx(); |
873 | 207 | if (TagTypeIdx >= TypeVec.size()) { |
874 | 48 | spdlog::error(ErrCode::Value::InvalidTagIdx); |
875 | 48 | spdlog::error( |
876 | 48 | ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::TagType, TagTypeIdx, |
877 | 48 | static_cast<uint32_t>(TypeVec.size()))); |
878 | 48 | return Unexpect(ErrCode::Value::InvalidTagIdx); |
879 | 48 | } |
880 | 159 | auto &CompType = TypeVec[TagTypeIdx]->getCompositeType(); |
881 | 159 | if (!CompType.isFunc()) { |
882 | 3 | spdlog::error(ErrCode::Value::InvalidTagIdx); |
883 | 3 | spdlog::error(" Defined type index {} is not a function type."sv, |
884 | 3 | TagTypeIdx); |
885 | 3 | return Unexpect(ErrCode::Value::InvalidTagIdx); |
886 | 3 | } |
887 | 156 | if (!CompType.getFuncType().getReturnTypes().empty()) { |
888 | 2 | spdlog::error(ErrCode::Value::InvalidTagResultType); |
889 | 2 | return Unexpect(ErrCode::Value::InvalidTagResultType); |
890 | 2 | } |
891 | 154 | Checker.addTag(TagTypeIdx); |
892 | 154 | } |
893 | 5.75k | return {}; |
894 | 5.80k | } |
895 | | |
896 | | // Validate constant expression. See "include/validator/validator.h". |
897 | | Expect<void> Validator::validateConstExpr(AST::InstrView Instrs, |
898 | 2.59k | Span<const ValType> Returns) { |
899 | 8.47k | for (auto &Instr : Instrs) { |
900 | | // Only these instructions are accepted. |
901 | 8.47k | switch (Instr.getOpCode()) { |
902 | 66 | case OpCode::Global__get: { |
903 | | // For the initialization case, global indices must be imported globals. |
904 | 66 | auto GlobIdx = Instr.getTargetIndex(); |
905 | 66 | uint32_t ValidGlobalSize = Checker.getNumImportGlobals(); |
906 | 66 | if (Conf.hasProposal(Proposal::FunctionReferences)) { |
907 | 66 | ValidGlobalSize = static_cast<uint32_t>(Checker.getGlobals().size()); |
908 | 66 | } |
909 | 66 | if (GlobIdx >= ValidGlobalSize) { |
910 | 49 | spdlog::error(ErrCode::Value::InvalidGlobalIdx); |
911 | 49 | spdlog::error(ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Global, |
912 | 49 | GlobIdx, ValidGlobalSize)); |
913 | 49 | spdlog::error( |
914 | 49 | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
915 | 49 | return Unexpect(ErrCode::Value::InvalidGlobalIdx); |
916 | 49 | } |
917 | 17 | if (Checker.getGlobals()[GlobIdx].second != ValMut::Const) { |
918 | 2 | spdlog::error(ErrCode::Value::ConstExprRequired); |
919 | 2 | spdlog::error( |
920 | 2 | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
921 | 2 | return Unexpect(ErrCode::Value::ConstExprRequired); |
922 | 2 | } |
923 | 15 | break; |
924 | 17 | } |
925 | 1.38k | case OpCode::Ref__func: { |
926 | | // In a const expression, add the reference to the context. |
927 | 1.38k | auto FuncIdx = Instr.getTargetIndex(); |
928 | 1.38k | if (FuncIdx >= Checker.getFunctions().size()) { |
929 | | // Function index out of range. |
930 | 43 | spdlog::error(ErrCode::Value::InvalidFuncIdx); |
931 | 43 | spdlog::error(ErrInfo::InfoForbidIndex( |
932 | 43 | ErrInfo::IndexCategory::Function, FuncIdx, |
933 | 43 | static_cast<uint32_t>(Checker.getFunctions().size()))); |
934 | 43 | spdlog::error( |
935 | 43 | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
936 | 43 | return Unexpect(ErrCode::Value::InvalidFuncIdx); |
937 | 43 | } |
938 | 1.34k | Checker.addRef(Instr.getTargetIndex()); |
939 | 1.34k | break; |
940 | 1.38k | } |
941 | 1.48k | case OpCode::I32__const: |
942 | 2.00k | case OpCode::I64__const: |
943 | 2.10k | case OpCode::F32__const: |
944 | 2.17k | case OpCode::F64__const: |
945 | 2.47k | case OpCode::Ref__null: |
946 | 2.51k | case OpCode::V128__const: |
947 | 4.91k | case OpCode::End: |
948 | 4.99k | case OpCode::Struct__new: |
949 | 5.05k | case OpCode::Struct__new_default: |
950 | 5.09k | case OpCode::Array__new: |
951 | 5.13k | case OpCode::Array__new_default: |
952 | 5.16k | case OpCode::Array__new_fixed: |
953 | 5.23k | case OpCode::Any__convert_extern: |
954 | 5.30k | case OpCode::Extern__convert_any: |
955 | 5.41k | case OpCode::Ref__i31: |
956 | 5.41k | break; |
957 | | |
958 | | // For the Extended-const proposal, these instructions are accepted. |
959 | 225 | case OpCode::I32__add: |
960 | 466 | case OpCode::I32__sub: |
961 | 726 | case OpCode::I32__mul: |
962 | 976 | case OpCode::I64__add: |
963 | 1.27k | case OpCode::I64__sub: |
964 | 1.51k | case OpCode::I64__mul: |
965 | 1.51k | if (Conf.hasProposal(Proposal::ExtendedConst)) { |
966 | 1.51k | break; |
967 | 1.51k | } |
968 | 0 | spdlog::error(ErrCode::Value::ConstExprRequired); |
969 | 0 | spdlog::error(ErrInfo::InfoProposal(Proposal::ExtendedConst)); |
970 | 0 | spdlog::error( |
971 | 0 | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
972 | 0 | return Unexpect(ErrCode::Value::ConstExprRequired); |
973 | | |
974 | 101 | default: |
975 | 101 | spdlog::error(ErrCode::Value::ConstExprRequired); |
976 | 101 | spdlog::error( |
977 | 101 | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
978 | 101 | return Unexpect(ErrCode::Value::ConstExprRequired); |
979 | 8.47k | } |
980 | 8.47k | } |
981 | | // Validate expression with result types. |
982 | 2.39k | Checker.reset(); |
983 | 2.39k | return Checker.validate(Instrs, Returns); |
984 | 2.59k | } |
985 | | |
986 | | } // namespace Validator |
987 | | } // namespace WasmEdge |