Coverage Report

Created: 2026-08-14 06:41

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