Coverage Report

Created: 2026-06-30 06:10

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