Coverage Report

Created: 2026-07-16 07:09

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
17.1k
                              std::initializer_list<TypeCode> Results) {
24
17.1k
  AST::FunctionType FT;
25
17.1k
  for (auto T : Params) {
26
17.1k
    FT.getParamTypes().emplace_back(T);
27
17.1k
  }
28
17.1k
  for (auto T : Results) {
29
8.55k
    FT.getReturnTypes().emplace_back(T);
30
8.55k
  }
31
17.1k
  AST::SubType ST;
32
17.1k
  ST.getCompositeType().setFunctionType(std::move(FT));
33
17.1k
  return ST;
34
17.1k
}
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
27
                  const std::vector<const WasmEdge::AST::SubType *> &TypeVec) {
45
27
  if (TestIdx >= DepthMap.size()) {
46
0
    DepthMap.resize(TestIdx + 1, Unvisited);
47
27
  } 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
27
  } else if (DepthMap[TestIdx] != Unvisited) {
53
0
    return DepthMap[TestIdx];
54
0
  }
55
56
27
  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
27
  DepthMap[TestIdx] = Visiting;
64
27
  uint32_t MaxDepth = 0;
65
27
  const auto &TestType = *TypeVec[TestIdx];
66
27
  for (const auto SuperIdx : TestType.getSuperTypeIndices()) {
67
0
    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
0
    EXPECTED_TRY(
75
0
        auto RetDepth,
76
0
        checkSubtypeDepth(BaseIdx, SuperIdx, Depth + 1, DepthMap, TypeVec)
77
0
            .map_error([=](auto E) {
78
0
              spdlog::error(
79
0
                  "    When checking subtype hierarchy of super type {}."sv,
80
0
                  SuperIdx);
81
0
              return E;
82
0
            }));
83
0
    MaxDepth = std::max(MaxDepth, RetDepth + 1);
84
0
  }
85
86
27
  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
27
  DepthMap[TestIdx] = MaxDepth;
94
27
  return MaxDepth;
95
27
}
96
97
} // namespace
98
99
// Validator constructor. See "include/validator/validator.h".
100
Validator::Validator(const Configure &Conf) noexcept
101
8.55k
    : Conf(Conf),
102
8.55k
      CoreFuncType_I32_I32(makeCoreFuncType({TypeCode::I32}, {TypeCode::I32})),
103
8.55k
      CoreFuncType_I32_Void(makeCoreFuncType({TypeCode::I32}, {})) {}
104
105
// Validate Module. See "include/validator/validator.h".
106
6.05k
Expect<void> Validator::validate(const AST::Module &Mod) {
107
  // https://webassembly.github.io/spec/core/valid/modules.html
108
6.05k
  Checker.reset(true);
109
110
  // Validate and register type section.
111
6.05k
  EXPECTED_TRY(validate(Mod.getTypeSection()).map_error([](auto E) {
112
5.99k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type));
113
5.99k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
114
5.99k
    return E;
115
5.99k
  }));
116
117
  // Validate and register the import section in FormChecker.
118
5.99k
  EXPECTED_TRY(validate(Mod.getImportSection()).map_error([](auto E) {
119
5.97k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Import));
120
5.97k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
121
5.97k
    return E;
122
5.97k
  }));
123
124
  // Validate the function section and register functions in FormChecker.
125
5.97k
  EXPECTED_TRY(validate(Mod.getFunctionSection()).map_error([](auto E) {
126
5.95k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Function));
127
5.95k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
128
5.95k
    return E;
129
5.95k
  }));
130
131
  // Validate the table section and register tables in FormChecker.
132
5.95k
  EXPECTED_TRY(validate(Mod.getTableSection()).map_error([](auto E) {
133
5.71k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Table));
134
5.71k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
135
5.71k
    return E;
136
5.71k
  }));
137
138
  // Validate the memory section and register memories in FormChecker.
139
5.71k
  EXPECTED_TRY(validate(Mod.getMemorySection()).map_error([](auto E) {
140
5.53k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Memory));
141
5.53k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
142
5.53k
    return E;
143
5.53k
  }));
144
145
  // Validate the global section and register globals in FormChecker.
146
5.53k
  EXPECTED_TRY(validate(Mod.getGlobalSection()).map_error([](auto E) {
147
5.22k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Global));
148
5.22k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
149
5.22k
    return E;
150
5.22k
  }));
151
152
  // Validate the tag section and register tags in FormChecker.
153
5.22k
  EXPECTED_TRY(validate(Mod.getTagSection()).map_error([](auto E) {
154
5.17k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Tag));
155
5.17k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
156
5.17k
    return E;
157
5.17k
  }));
158
159
  // Validate export section.
160
5.17k
  EXPECTED_TRY(validate(Mod.getExportSection()).map_error([](auto E) {
161
5.05k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Export));
162
5.05k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
163
5.05k
    return E;
164
5.05k
  }));
165
166
  // Validate start section.
167
5.05k
  EXPECTED_TRY(validate(Mod.getStartSection()).map_error([](auto E) {
168
5.00k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Start));
169
5.00k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
170
5.00k
    return E;
171
5.00k
  }));
172
173
  // Validate the element section that initializes tables.
174
5.00k
  EXPECTED_TRY(validate(Mod.getElementSection()).map_error([](auto E) {
175
4.87k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Element));
176
4.87k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
177
4.87k
    return E;
178
4.87k
  }));
179
180
  // Validate the data section that initializes memories.
181
4.87k
  EXPECTED_TRY(validate(Mod.getDataSection()).map_error([](auto E) {
182
4.85k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Data));
183
4.85k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
184
4.85k
    return E;
185
4.85k
  }));
186
187
  // Validate code section and expressions.
188
4.85k
  EXPECTED_TRY(validate(Mod.getCodeSection()).map_error([](auto E) {
189
3.35k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Code));
190
3.35k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
191
3.35k
    return E;
192
3.35k
  }));
193
194
  // Multiple tables are for the ReferenceTypes proposal.
195
3.35k
  if (Checker.getTables().size() > 1 &&
196
50
      !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.35k
  if (Checker.getMemories().size() > 1 &&
205
82
      !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.35k
  const_cast<AST::Module &>(Mod).setIsValidated();
214
3.35k
  return {};
215
3.35k
}
216
217
// Validate Sub type. See "include/validator/validator.h".
218
Expect<void> Validator::validate(const AST::SubType &Type, uint32_t OwnTypeIdx,
219
7.45k
                                 std::vector<uint32_t> &SubTypeDepthMap) {
220
7.45k
  const auto &TypeVec = Checker.getTypes();
221
7.45k
  const auto &CompType = Type.getCompositeType();
222
223
  // Check the validation of the composite type.
224
7.45k
  if (CompType.isFunc()) {
225
7.08k
    const auto &FType = CompType.getFuncType();
226
7.08k
    for (auto &PType : FType.getParamTypes()) {
227
6.49k
      EXPECTED_TRY(Checker.validate(PType).map_error([](auto E) {
228
6.49k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
229
6.49k
        return E;
230
6.49k
      }));
231
6.49k
    }
232
7.08k
    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
7.08k
    for (auto &RType : FType.getReturnTypes()) {
240
5.30k
      EXPECTED_TRY(Checker.validate(RType).map_error([](auto E) {
241
5.30k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
242
5.30k
        return E;
243
5.30k
      }));
244
5.30k
    }
245
7.08k
  } else {
246
367
    const auto &FTypes = CompType.getFieldTypes();
247
367
    for (auto &FieldType : FTypes) {
248
227
      EXPECTED_TRY(Checker.validate(FieldType.getStorageType()));
249
227
    }
250
367
  }
251
252
  // In the current version, the length of the type index vector will be <= 1.
253
7.43k
  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
7.43k
  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
36
    if (unlikely(Index >= OwnTypeIdx)) {
263
9
      spdlog::error(ErrCode::Value::InvalidSubType);
264
9
      spdlog::error("    Super type index {} must be smaller than the sub type "
265
9
                    "index {}."sv,
266
9
                    Index, OwnTypeIdx);
267
9
      return Unexpect(ErrCode::Value::InvalidSubType);
268
9
    }
269
270
27
    EXPECTED_TRY(
271
27
        checkSubtypeDepth(Index, Index, 0, SubTypeDepthMap, TypeVec)
272
27
            .map_error([=](auto E) {
273
27
              spdlog::error(
274
27
                  "    When checking subtype hierarchy of super type {}."sv,
275
27
                  Index);
276
27
              return E;
277
27
            }));
278
279
27
    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
26
    auto &SuperType = TypeVec[Index]->getCompositeType();
285
26
    if (!AST::TypeMatcher::matchType(Checker.getTypes(), SuperType, CompType)) {
286
20
      spdlog::error(ErrCode::Value::InvalidSubType);
287
20
      spdlog::error("    Super type not matched."sv);
288
20
      return Unexpect(ErrCode::Value::InvalidSubType);
289
20
    }
290
26
  }
291
7.40k
  return {};
292
7.43k
}
293
294
// Validate Limit type. See "include/validator/validator.h".
295
2.74k
Expect<void> Validator::validate(const AST::Limit &Lim) {
296
2.74k
  if (Lim.hasMax() && Lim.getMin() > Lim.getMax()) {
297
109
    spdlog::error(ErrCode::Value::InvalidLimit);
298
109
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
299
109
    return Unexpect(ErrCode::Value::InvalidLimit);
300
109
  }
301
2.63k
  if (Lim.isShared() && unlikely(!Lim.hasMax())) {
302
0
    spdlog::error(ErrCode::Value::SharedMemoryNoMax);
303
0
    return Unexpect(ErrCode::Value::SharedMemoryNoMax);
304
0
  }
305
2.63k
  return {};
306
2.63k
}
307
308
// Validate Table type. See "include/validator/validator.h".
309
871
Expect<void> Validator::validate(const AST::TableType &Tab) {
310
  // Validate value type.
311
871
  EXPECTED_TRY(Checker.validate(Tab.getRefType()));
312
  // Validate table limits.
313
818
  const auto &Lim = Tab.getLimit();
314
818
  EXPECTED_TRY(validate(Lim).map_error([](auto E) {
315
758
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
316
758
    return E;
317
758
  }));
318
758
  uint64_t Range = getMaxAddress(Lim.getAddrType());
319
758
  if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) {
320
    // Since spec test has no related error message, use this error instead.
321
123
    auto Code = Conf.hasProposal(Proposal::Memory64)
322
123
                    ? ErrCode::Value::InvalidTableSize64
323
123
                    : ErrCode::Value::InvalidLimit;
324
123
    spdlog::error(Code);
325
123
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
326
123
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
327
123
    return Unexpect(Code);
328
123
  }
329
635
  return {};
330
758
}
331
332
// Validate Memory type. See "include/validator/validator.h".
333
1.92k
Expect<void> Validator::validate(const AST::MemoryType &Mem) {
334
  // Validate memory limits.
335
1.92k
  const auto &Lim = Mem.getLimit();
336
1.92k
  EXPECTED_TRY(validate(Lim).map_error([](auto E) {
337
1.87k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
338
1.87k
    return E;
339
1.87k
  }));
340
1.87k
  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
1.87k
  uint64_t Range = Lim.is32() ? (static_cast<uint64_t>(1) << 16)
347
1.87k
                              : (static_cast<uint64_t>(1) << 48);
348
1.87k
  if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) {
349
142
    auto Code = Conf.hasProposal(Proposal::Memory64)
350
142
                    ? ErrCode::Value::InvalidMemPages64
351
142
                    : ErrCode::Value::InvalidMemPages;
352
142
    spdlog::error(Code);
353
142
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
354
142
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
355
142
    return Unexpect(Code);
356
142
  }
357
1.73k
  return {};
358
1.87k
}
359
360
// Validate Global type. See "include/validator/validator.h".
361
352
Expect<void> Validator::validate(const AST::GlobalType &Glob) {
362
  // Validate value type.
363
352
  return Checker.validate(Glob.getValType());
364
352
}
365
366
// Validate Table segment. See "include/validator/validator.h".
367
821
Expect<void> Validator::validate(const AST::TableSegment &TabSeg) {
368
821
  if (TabSeg.getExpr().getInstrs().size() > 0) {
369
    // Check ref initialization is a const expression.
370
5
    EXPECTED_TRY(
371
5
        validateConstExpr(TabSeg.getExpr().getInstrs(),
372
5
                          {ValType(TabSeg.getTableType().getRefType())})
373
5
            .map_error([](auto E) {
374
5
              spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
375
5
              return E;
376
5
            }));
377
816
  } else {
378
    // No init expression. Check that the reference type is nullable.
379
816
    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
816
  }
389
  // Validate table type.
390
815
  return validate(TabSeg.getTableType()).map_error([](auto E) {
391
234
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table));
392
234
    return E;
393
234
  });
394
821
}
395
396
// Validate Global segment. See "include/validator/validator.h".
397
608
Expect<void> Validator::validate(const AST::GlobalSegment &GlobSeg) {
398
  // Check global initialization is a const expression.
399
608
  EXPECTED_TRY(validateConstExpr(GlobSeg.getExpr().getInstrs(),
400
297
                                 {GlobSeg.getGlobalType().getValType()})
401
297
                   .map_error([](auto E) {
402
297
                     spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
403
297
                     return E;
404
297
                   }));
405
  // Validate global type.
406
297
  return validate(GlobSeg.getGlobalType()).map_error([](auto E) {
407
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global));
408
0
    return E;
409
0
  });
410
608
}
411
412
// Validate Element segment. See "include/validator/validator.h".
413
631
Expect<void> Validator::validate(const AST::ElementSegment &ElemSeg) {
414
  // Check that initialization expressions are const expressions.
415
1.40k
  for (auto &Expr : ElemSeg.getInitExprs()) {
416
1.40k
    EXPECTED_TRY(
417
1.40k
        validateConstExpr(Expr.getInstrs(), {ValType(ElemSeg.getRefType())})
418
1.40k
            .map_error([](auto E) {
419
1.40k
              spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
420
1.40k
              return E;
421
1.40k
            }));
422
1.40k
  }
423
424
  // The reference type should be valid.
425
549
  EXPECTED_TRY(Checker.validate(ElemSeg.getRefType()));
426
427
  // Passive and declarative cases are valid with a valid reference type.
428
546
  if (ElemSeg.getMode() == AST::ElementSegment::ElemMode::Active) {
429
    // Check table index and reference type in context.
430
311
    const auto &TableVec = Checker.getTables();
431
311
    if (ElemSeg.getIdx() >= TableVec.size()) {
432
30
      spdlog::error(ErrCode::Value::InvalidTableIdx);
433
30
      spdlog::error(ErrInfo::InfoForbidIndex(
434
30
          ErrInfo::IndexCategory::Table, ElemSeg.getIdx(),
435
30
          static_cast<uint32_t>(TableVec.size())));
436
30
      return Unexpect(ErrCode::Value::InvalidTableIdx);
437
30
    }
438
281
    if (!AST::TypeMatcher::matchType(Checker.getTypes(),
439
281
                                     TableVec[ElemSeg.getIdx()].second,
440
281
                                     ElemSeg.getRefType())) {
441
      // Reference type does not match.
442
8
      spdlog::error(ErrCode::Value::TypeCheckFailed);
443
8
      spdlog::error(ErrInfo::InfoMismatch(TableVec[ElemSeg.getIdx()].second,
444
8
                                          ElemSeg.getRefType()));
445
8
      return Unexpect(ErrCode::Value::TypeCheckFailed);
446
8
    }
447
    // Check table initialization is a const expression.
448
273
    return validateConstExpr(ElemSeg.getExpr().getInstrs(),
449
273
                             {ValType(TableVec[ElemSeg.getIdx()].first)})
450
273
        .map_error([](auto E) {
451
4
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
452
4
          return E;
453
4
        });
454
281
  }
455
235
  return {};
456
546
}
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.5k
    Checker.addLocal(Type, true);
471
10.5k
  }
472
  // Add locals to this frame.
473
12.8k
  for (auto Val : CodeSeg.getLocals()) {
474
138M
    for (uint32_t Cnt = 0; Cnt < Val.first; ++Cnt) {
475
      // The local value type should be valid.
476
138M
      EXPECTED_TRY(Checker.validate(Val.second));
477
138M
      Checker.addLocal(Val.second, false);
478
138M
    }
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.49k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
485
1.49k
        return E;
486
1.49k
      });
487
12.8k
}
488
489
// Validate Data segment. See "include/validator/validator.h".
490
362
Expect<void> Validator::validate(const AST::DataSegment &DataSeg) {
491
362
  switch (DataSeg.getMode()) {
492
203
  case AST::DataSegment::DataMode::Active: {
493
    // Check memory index in context.
494
203
    const auto &MemVec = Checker.getMemories();
495
203
    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
184
    return validateConstExpr(DataSeg.getExpr().getInstrs(),
504
184
                             {ValType(MemVec[DataSeg.getIdx()])})
505
184
        .map_error([](auto E) {
506
5
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
507
5
          return E;
508
5
        });
509
203
  }
510
159
  case AST::DataSegment::DataMode::Passive:
511
    // Passive case is always valid.
512
159
    return {};
513
0
  default:
514
0
    return {};
515
362
  }
516
362
}
517
518
// Validate Import description. See "include/validator/validator.h".
519
565
Expect<void> Validator::validate(const AST::ImportDesc &ImpDesc) {
520
565
  switch (ImpDesc.getExternalType()) {
521
  // External type and external content are ensured to match in the loader
522
  // phase.
523
376
  case ExternalType::Function: {
524
376
    const auto TId = ImpDesc.getExternalFuncTypeIdx();
525
    // Function type index must exist in context and be valid.
526
376
    if (TId >= Checker.getTypes().size()) {
527
10
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
528
10
      spdlog::error(ErrInfo::InfoForbidIndex(
529
10
          ErrInfo::IndexCategory::FunctionType, TId,
530
10
          static_cast<uint32_t>(Checker.getTypes().size())));
531
10
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
532
10
    }
533
366
    if (!Checker.getTypes()[TId]->getCompositeType().isFunc()) {
534
1
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
535
1
      spdlog::error("    Defined type index {} is not a function type."sv, TId);
536
1
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
537
1
    }
538
365
    Checker.addRef(static_cast<uint32_t>(Checker.getFunctions().size()));
539
365
    Checker.addFunc(TId, true);
540
365
    return {};
541
366
  }
542
56
  case ExternalType::Table: {
543
56
    const auto &TabType = ImpDesc.getExternalTableType();
544
    // Table type must be valid.
545
56
    EXPECTED_TRY(validate(TabType).map_error([](auto E) {
546
54
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table));
547
54
      return E;
548
54
    }));
549
54
    Checker.addTable(TabType);
550
54
    return {};
551
56
  }
552
56
  case ExternalType::Memory: {
553
56
    const auto &MemType = ImpDesc.getExternalMemoryType();
554
    // Memory type must be valid.
555
56
    EXPECTED_TRY(validate(MemType).map_error([](auto E) {
556
53
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory));
557
53
      return E;
558
53
    }));
559
53
    Checker.addMemory(MemType);
560
53
    return {};
561
56
  }
562
22
  case ExternalType::Tag: {
563
22
    const auto &T = ImpDesc.getExternalTagType();
564
    // Tag type index must exist in context.
565
22
    auto TagTypeIdx = T.getTypeIdx();
566
22
    if (TagTypeIdx >= Checker.getTypes().size()) {
567
7
      spdlog::error(ErrCode::Value::InvalidTagIdx);
568
7
      spdlog::error(ErrInfo::InfoForbidIndex(
569
7
          ErrInfo::IndexCategory::TagType, TagTypeIdx,
570
7
          static_cast<uint32_t>(Checker.getTypes().size())));
571
7
      return Unexpect(ErrCode::Value::InvalidTagIdx);
572
7
    }
573
    // Tag type must be valid.
574
15
    auto &CompType = Checker.getTypes()[TagTypeIdx]->getCompositeType();
575
15
    if (!CompType.isFunc()) {
576
1
      spdlog::error(ErrCode::Value::InvalidTagIdx);
577
1
      spdlog::error("    Defined type index {} is not a function type."sv,
578
1
                    TagTypeIdx);
579
1
      return Unexpect(ErrCode::Value::InvalidTagIdx);
580
1
    }
581
14
    if (!CompType.getFuncType().getReturnTypes().empty()) {
582
1
      spdlog::error(ErrCode::Value::InvalidTagResultType);
583
1
      return Unexpect(ErrCode::Value::InvalidTagResultType);
584
1
    }
585
13
    Checker.addTag(TagTypeIdx);
586
13
    return {};
587
14
  }
588
55
  case ExternalType::Global: {
589
55
    const auto &GlobType = ImpDesc.getExternalGlobalType();
590
    // Global type must be valid.
591
55
    EXPECTED_TRY(validate(GlobType).map_error([](auto E) {
592
52
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global));
593
52
      return E;
594
52
    }));
595
52
    Checker.addGlobal(GlobType, true);
596
52
    return {};
597
55
  }
598
0
  default:
599
0
    return {};
600
565
  }
601
565
}
602
603
// Validate Export description. See "include/validator/validator.h".
604
10.3k
Expect<void> Validator::validate(const AST::ExportDesc &ExpDesc) {
605
10.3k
  auto Id = ExpDesc.getExternalIndex();
606
10.3k
  switch (ExpDesc.getExternalType()) {
607
9.96k
  case ExternalType::Function:
608
9.96k
    if (Id >= Checker.getFunctions().size()) {
609
33
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
610
33
      spdlog::error(ErrInfo::InfoForbidIndex(
611
33
          ErrInfo::IndexCategory::Function, Id,
612
33
          static_cast<uint32_t>(Checker.getFunctions().size())));
613
33
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
614
33
    }
615
9.93k
    Checker.addRef(Id);
616
9.93k
    return {};
617
39
  case ExternalType::Table:
618
39
    if (Id >= Checker.getTables().size()) {
619
12
      spdlog::error(ErrCode::Value::InvalidTableIdx);
620
12
      spdlog::error(ErrInfo::InfoForbidIndex(
621
12
          ErrInfo::IndexCategory::Table, Id,
622
12
          static_cast<uint32_t>(Checker.getTables().size())));
623
12
      return Unexpect(ErrCode::Value::InvalidTableIdx);
624
12
    }
625
27
    return {};
626
123
  case ExternalType::Memory:
627
123
    if (Id >= Checker.getMemories().size()) {
628
19
      spdlog::error(ErrCode::Value::InvalidMemoryIdx);
629
19
      spdlog::error(ErrInfo::InfoForbidIndex(
630
19
          ErrInfo::IndexCategory::Memory, Id,
631
19
          static_cast<uint32_t>(Checker.getMemories().size())));
632
19
      return Unexpect(ErrCode::Value::InvalidMemoryIdx);
633
19
    }
634
104
    return {};
635
44
  case ExternalType::Tag:
636
44
    if (Id >= Checker.getTags().size()) {
637
33
      spdlog::error(ErrCode::Value::InvalidTagIdx);
638
33
      spdlog::error(ErrInfo::InfoForbidIndex(
639
33
          ErrInfo::IndexCategory::Tag, Id,
640
33
          static_cast<uint32_t>(Checker.getTags().size())));
641
33
      return Unexpect(ErrCode::Value::InvalidTagIdx);
642
33
    }
643
11
    return {};
644
147
  case ExternalType::Global:
645
147
    if (Id >= Checker.getGlobals().size()) {
646
25
      spdlog::error(ErrCode::Value::InvalidGlobalIdx);
647
25
      spdlog::error(ErrInfo::InfoForbidIndex(
648
25
          ErrInfo::IndexCategory::Global, Id,
649
25
          static_cast<uint32_t>(Checker.getGlobals().size())));
650
25
      return Unexpect(ErrCode::Value::InvalidGlobalIdx);
651
25
    }
652
122
    return {};
653
0
  default:
654
0
    return {};
655
10.3k
  }
656
10.3k
}
657
658
6.05k
Expect<void> Validator::validate(const AST::TypeSection &TypeSec) {
659
6.05k
  const auto STypeList = TypeSec.getContent();
660
6.05k
  std::vector<uint32_t> SubTypeDepthMap(STypeList.size(), Unvisited);
661
6.05k
  uint32_t Idx = 0;
662
13.4k
  while (Idx < STypeList.size()) {
663
7.43k
    const auto &SType = STypeList[Idx];
664
    // The next type to add takes this index in the type index space.
665
7.43k
    const uint32_t BaseIdx = static_cast<uint32_t>(Checker.getTypes().size());
666
7.43k
    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
7.43k
      const uint32_t RecSize = SType.getRecursiveInfo().has_value()
670
7.43k
                                   ? SType.getRecursiveInfo()->RecTypeSize
671
7.43k
                                   : 1;
672
14.9k
      for (uint32_t I = Idx; I < Idx + RecSize; I++) {
673
7.47k
        Checker.addType(STypeList[I]);
674
7.47k
      }
675
14.8k
      for (uint32_t I = Idx; I < Idx + RecSize; I++) {
676
7.45k
        EXPECTED_TRY(
677
7.45k
            validate(STypeList[I], BaseIdx + (I - Idx), SubTypeDepthMap)
678
7.45k
                .map_error([](auto E) {
679
7.45k
                  spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Rec));
680
7.45k
                  return E;
681
7.45k
                }));
682
7.45k
      }
683
7.38k
      Idx += RecSize;
684
7.38k
    } 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
7.43k
  }
692
5.99k
  return {};
693
6.05k
}
694
695
// Validate Import section. See "include/validator/validator.h".
696
5.99k
Expect<void> Validator::validate(const AST::ImportSection &ImportSec) {
697
5.99k
  for (auto &ImportDesc : ImportSec.getContent()) {
698
565
    EXPECTED_TRY(validate(ImportDesc).map_error([](auto E) {
699
565
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Import));
700
565
      return E;
701
565
    }));
702
565
  }
703
5.97k
  return {};
704
5.99k
}
705
706
// Validate Function section. See "include/validator/validator.h".
707
5.97k
Expect<void> Validator::validate(const AST::FunctionSection &FuncSec) {
708
5.97k
  const auto &FuncVec = FuncSec.getContent();
709
5.97k
  const auto &TypeVec = Checker.getTypes();
710
711
  // Check whether the function type ID is valid in context.
712
17.1k
  for (auto &TId : FuncVec) {
713
17.1k
    if (TId >= TypeVec.size()) {
714
10
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
715
10
      spdlog::error(
716
10
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::FunctionType, TId,
717
10
                                   static_cast<uint32_t>(TypeVec.size())));
718
10
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
719
10
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
720
10
    }
721
17.1k
    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
17.1k
    Checker.addFunc(TId);
728
17.1k
  }
729
5.95k
  return {};
730
5.97k
}
731
732
// Validate Table section. See "include/validator/validator.h".
733
5.95k
Expect<void> Validator::validate(const AST::TableSection &TabSec) {
734
5.95k
  for (auto &Tab : TabSec.getContent()) {
735
821
    EXPECTED_TRY(validate(Tab).map_error([](auto E) {
736
581
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table));
737
581
      return E;
738
581
    }));
739
581
    Checker.addTable(Tab.getTableType());
740
581
  }
741
5.71k
  return {};
742
5.95k
}
743
744
// Validate Memory section. See "include/validator/validator.h".
745
5.71k
Expect<void> Validator::validate(const AST::MemorySection &MemSec) {
746
5.71k
  for (auto &Mem : MemSec.getContent()) {
747
1.86k
    EXPECTED_TRY(validate(Mem).map_error([](auto E) {
748
1.68k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory));
749
1.68k
      return E;
750
1.68k
    }));
751
1.68k
    Checker.addMemory(Mem);
752
1.68k
  }
753
5.53k
  return {};
754
5.71k
}
755
756
// Validate Global section. See "include/validator/validator.h".
757
5.53k
Expect<void> Validator::validate(const AST::GlobalSection &GlobSec) {
758
5.53k
  for (auto &GlobSeg : GlobSec.getContent()) {
759
608
    EXPECTED_TRY(validate(GlobSeg).map_error([](auto E) {
760
297
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global));
761
297
      return E;
762
297
    }));
763
297
    Checker.addGlobal(GlobSeg.getGlobalType());
764
297
  }
765
5.22k
  return {};
766
5.53k
}
767
768
// Validate Element section. See "include/validator/validator.h".
769
5.00k
Expect<void> Validator::validate(const AST::ElementSection &ElemSec) {
770
5.00k
  for (auto &ElemSeg : ElemSec.getContent()) {
771
631
    EXPECTED_TRY(validate(ElemSeg).map_error([](auto E) {
772
504
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element));
773
504
      return E;
774
504
    }));
775
504
    Checker.addElem(ElemSeg);
776
504
  }
777
4.87k
  return {};
778
5.00k
}
779
780
// Validate Code section. See "include/validator/validator.h".
781
4.85k
Expect<void> Validator::validate(const AST::CodeSection &CodeSec) {
782
4.85k
  const auto &CodeVec = CodeSec.getContent();
783
4.85k
  const auto &FuncVec = Checker.getFunctions();
784
785
  // Validate function body.
786
16.2k
  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.35k
  return {};
802
4.85k
}
803
804
// Validate Data section. See "include/validator/validator.h".
805
4.87k
Expect<void> Validator::validate(const AST::DataSection &DataSec) {
806
4.87k
  for (auto &DataSeg : DataSec.getContent()) {
807
362
    EXPECTED_TRY(validate(DataSeg).map_error([](auto E) {
808
338
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data));
809
338
      return E;
810
338
    }));
811
338
    Checker.addData(DataSeg);
812
338
  }
813
4.85k
  return {};
814
4.87k
}
815
816
// Validate Start section. See "include/validator/validator.h".
817
5.05k
Expect<void> Validator::validate(const AST::StartSection &StartSec) {
818
5.05k
  if (StartSec.getContent()) {
819
53
    auto FId = *StartSec.getContent();
820
53
    if (FId >= Checker.getFunctions().size()) {
821
47
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
822
47
      spdlog::error(ErrInfo::InfoForbidIndex(
823
47
          ErrInfo::IndexCategory::Function, FId,
824
47
          static_cast<uint32_t>(Checker.getFunctions().size())));
825
47
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
826
47
    }
827
6
    auto TId = Checker.getFunctions()[FId];
828
6
    assuming(TId < Checker.getTypes().size());
829
6
    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
6
    auto &Type = Checker.getTypes()[TId]->getCompositeType().getFuncType();
835
6
    if (Type.getParamTypes().size() != 0 || Type.getReturnTypes().size() != 0) {
836
      // Start function signature should be {}->{}
837
2
      spdlog::error(ErrCode::Value::InvalidStartFunc);
838
2
      spdlog::error(ErrInfo::InfoMismatch({}, {}, Type.getParamTypes(),
839
2
                                          Type.getReturnTypes()));
840
2
      return Unexpect(ErrCode::Value::InvalidStartFunc);
841
2
    }
842
6
  }
843
5.00k
  return {};
844
5.05k
}
845
846
// Validate Export section. See "include/validator/validator.h".
847
5.17k
Expect<void> Validator::validate(const AST::ExportSection &ExportSec) {
848
5.17k
  std::unordered_set<std::string_view, Hash::Hash> ExportNames;
849
10.3k
  for (auto &ExportDesc : ExportSec.getContent()) {
850
10.3k
    auto Result = ExportNames.emplace(ExportDesc.getExternalName());
851
10.3k
    if (!Result.second) {
852
      // Duplicated export name.
853
5
      spdlog::error(ErrCode::Value::DupExportName);
854
5
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export));
855
5
      return Unexpect(ErrCode::Value::DupExportName);
856
5
    }
857
10.3k
    EXPECTED_TRY(validate(ExportDesc).map_error([](auto E) {
858
10.3k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export));
859
10.3k
      return E;
860
10.3k
    }));
861
10.3k
  }
862
5.05k
  return {};
863
5.17k
}
864
865
// Validate Tag section. See "include/validator/validator.h".
866
5.22k
Expect<void> Validator::validate(const AST::TagSection &TagSec) {
867
5.22k
  const auto &TagVec = TagSec.getContent();
868
5.22k
  const auto &TypeVec = Checker.getTypes();
869
870
  // Check whether the tag type ID is valid in context.
871
5.22k
  for (auto &TagType : TagVec) {
872
119
    auto TagTypeIdx = TagType.getTypeIdx();
873
119
    if (TagTypeIdx >= TypeVec.size()) {
874
38
      spdlog::error(ErrCode::Value::InvalidTagIdx);
875
38
      spdlog::error(
876
38
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::TagType, TagTypeIdx,
877
38
                                   static_cast<uint32_t>(TypeVec.size())));
878
38
      return Unexpect(ErrCode::Value::InvalidTagIdx);
879
38
    }
880
81
    auto &CompType = TypeVec[TagTypeIdx]->getCompositeType();
881
81
    if (!CompType.isFunc()) {
882
2
      spdlog::error(ErrCode::Value::InvalidTagIdx);
883
2
      spdlog::error("    Defined type index {} is not a function type."sv,
884
2
                    TagTypeIdx);
885
2
      return Unexpect(ErrCode::Value::InvalidTagIdx);
886
2
    }
887
79
    if (!CompType.getFuncType().getReturnTypes().empty()) {
888
1
      spdlog::error(ErrCode::Value::InvalidTagResultType);
889
1
      return Unexpect(ErrCode::Value::InvalidTagResultType);
890
1
    }
891
78
    Checker.addTag(TagTypeIdx);
892
78
  }
893
5.17k
  return {};
894
5.22k
}
895
896
// Validate constant expression. See "include/validator/validator.h".
897
Expect<void> Validator::validateConstExpr(AST::InstrView Instrs,
898
2.47k
                                          Span<const ValType> Returns) {
899
7.73k
  for (auto &Instr : Instrs) {
900
    // Only these instructions are accepted.
901
7.73k
    switch (Instr.getOpCode()) {
902
64
    case OpCode::Global__get: {
903
      // For the initialization case, global indices must be imported globals.
904
64
      auto GlobIdx = Instr.getTargetIndex();
905
64
      uint32_t ValidGlobalSize = Checker.getNumImportGlobals();
906
64
      if (Conf.hasProposal(Proposal::FunctionReferences)) {
907
64
        ValidGlobalSize = static_cast<uint32_t>(Checker.getGlobals().size());
908
64
      }
909
64
      if (GlobIdx >= ValidGlobalSize) {
910
47
        spdlog::error(ErrCode::Value::InvalidGlobalIdx);
911
47
        spdlog::error(ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Global,
912
47
                                               GlobIdx, ValidGlobalSize));
913
47
        spdlog::error(
914
47
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
915
47
        return Unexpect(ErrCode::Value::InvalidGlobalIdx);
916
47
      }
917
17
      if (Checker.getGlobals()[GlobIdx].second != ValMut::Const) {
918
1
        spdlog::error(ErrCode::Value::ConstExprRequired);
919
1
        spdlog::error(
920
1
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
921
1
        return Unexpect(ErrCode::Value::ConstExprRequired);
922
1
      }
923
16
      break;
924
17
    }
925
1.32k
    case OpCode::Ref__func: {
926
      // In a const expression, add the reference to the context.
927
1.32k
      auto FuncIdx = Instr.getTargetIndex();
928
1.32k
      if (FuncIdx >= Checker.getFunctions().size()) {
929
        // Function index out of range.
930
44
        spdlog::error(ErrCode::Value::InvalidFuncIdx);
931
44
        spdlog::error(ErrInfo::InfoForbidIndex(
932
44
            ErrInfo::IndexCategory::Function, FuncIdx,
933
44
            static_cast<uint32_t>(Checker.getFunctions().size())));
934
44
        spdlog::error(
935
44
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
936
44
        return Unexpect(ErrCode::Value::InvalidFuncIdx);
937
44
      }
938
1.27k
      Checker.addRef(Instr.getTargetIndex());
939
1.27k
      break;
940
1.32k
    }
941
1.34k
    case OpCode::I32__const:
942
1.74k
    case OpCode::I64__const:
943
1.83k
    case OpCode::F32__const:
944
1.92k
    case OpCode::F64__const:
945
2.10k
    case OpCode::Ref__null:
946
2.13k
    case OpCode::V128__const:
947
4.41k
    case OpCode::End:
948
4.45k
    case OpCode::Struct__new:
949
4.47k
    case OpCode::Struct__new_default:
950
4.49k
    case OpCode::Array__new:
951
4.53k
    case OpCode::Array__new_default:
952
4.56k
    case OpCode::Array__new_fixed:
953
4.61k
    case OpCode::Any__convert_extern:
954
4.67k
    case OpCode::Extern__convert_any:
955
4.76k
    case OpCode::Ref__i31:
956
4.76k
      break;
957
958
    // For the Extended-const proposal, these instructions are accepted.
959
196
    case OpCode::I32__add:
960
447
    case OpCode::I32__sub:
961
788
    case OpCode::I32__mul:
962
1.03k
    case OpCode::I64__add:
963
1.27k
    case OpCode::I64__sub:
964
1.48k
    case OpCode::I64__mul:
965
1.48k
      if (Conf.hasProposal(Proposal::ExtendedConst)) {
966
1.48k
        break;
967
1.48k
      }
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
99
    default:
975
99
      spdlog::error(ErrCode::Value::ConstExprRequired);
976
99
      spdlog::error(
977
99
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
978
99
      return Unexpect(ErrCode::Value::ConstExprRequired);
979
7.73k
    }
980
7.73k
  }
981
  // Validate expression with result types.
982
2.28k
  Checker.reset();
983
2.28k
  return Checker.validate(Instrs, Returns);
984
2.47k
}
985
986
} // namespace Validator
987
} // namespace WasmEdge