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