Coverage Report

Created: 2026-08-08 06:32

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
21.4k
                              std::initializer_list<TypeCode> Results) {
24
21.4k
  AST::FunctionType FT;
25
21.4k
  for (auto T : Params) {
26
21.4k
    FT.getParamTypes().emplace_back(T);
27
21.4k
  }
28
21.4k
  for (auto T : Results) {
29
10.7k
    FT.getReturnTypes().emplace_back(T);
30
10.7k
  }
31
21.4k
  AST::SubType ST;
32
21.4k
  ST.getCompositeType().setFunctionType(std::move(FT));
33
21.4k
  return ST;
34
21.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
10.7k
    : Conf(Conf),
102
10.7k
      CoreFuncType_I32_I32(makeCoreFuncType({TypeCode::I32}, {TypeCode::I32})),
103
10.7k
      CoreFuncType_I32_Void(makeCoreFuncType({TypeCode::I32}, {})) {}
104
105
// Validate Module. See "include/validator/validator.h".
106
7.41k
Expect<void> Validator::validate(const AST::Module &Mod) {
107
  // https://webassembly.github.io/spec/core/valid/modules.html
108
7.41k
  Checker.reset(true);
109
110
  // Validate and register type section.
111
7.41k
  EXPECTED_TRY(validate(Mod.getTypeSection()).map_error([](auto E) {
112
7.35k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type));
113
7.35k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
114
7.35k
    return E;
115
7.35k
  }));
116
117
  // Validate and register the import section in FormChecker.
118
7.35k
  EXPECTED_TRY(validate(Mod.getImportSection()).map_error([](auto E) {
119
7.28k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Import));
120
7.28k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
121
7.28k
    return E;
122
7.28k
  }));
123
124
  // Validate the function section and register functions in FormChecker.
125
7.28k
  EXPECTED_TRY(validate(Mod.getFunctionSection()).map_error([](auto E) {
126
7.27k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Function));
127
7.27k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
128
7.27k
    return E;
129
7.27k
  }));
130
131
  // Validate the table section and register tables in FormChecker.
132
7.27k
  EXPECTED_TRY(validate(Mod.getTableSection()).map_error([](auto E) {
133
7.05k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Table));
134
7.05k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
135
7.05k
    return E;
136
7.05k
  }));
137
138
  // Validate the memory section and register memories in FormChecker.
139
7.05k
  EXPECTED_TRY(validate(Mod.getMemorySection()).map_error([](auto E) {
140
6.78k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Memory));
141
6.78k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
142
6.78k
    return E;
143
6.78k
  }));
144
145
  // Validate the global section and register globals in FormChecker.
146
6.78k
  EXPECTED_TRY(validate(Mod.getGlobalSection()).map_error([](auto E) {
147
6.42k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Global));
148
6.42k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
149
6.42k
    return E;
150
6.42k
  }));
151
152
  // Validate the tag section and register tags in FormChecker.
153
6.42k
  EXPECTED_TRY(validate(Mod.getTagSection()).map_error([](auto E) {
154
6.37k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Tag));
155
6.37k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
156
6.37k
    return E;
157
6.37k
  }));
158
159
  // Validate export section.
160
6.37k
  EXPECTED_TRY(validate(Mod.getExportSection()).map_error([](auto E) {
161
6.20k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Export));
162
6.20k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
163
6.20k
    return E;
164
6.20k
  }));
165
166
  // Validate start section.
167
6.20k
  EXPECTED_TRY(validate(Mod.getStartSection()).map_error([](auto E) {
168
6.13k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Start));
169
6.13k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
170
6.13k
    return E;
171
6.13k
  }));
172
173
  // Validate the element section that initializes tables.
174
6.13k
  EXPECTED_TRY(validate(Mod.getElementSection()).map_error([](auto E) {
175
5.99k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Element));
176
5.99k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
177
5.99k
    return E;
178
5.99k
  }));
179
180
  // Validate the data section that initializes memories.
181
5.99k
  EXPECTED_TRY(validate(Mod.getDataSection()).map_error([](auto E) {
182
5.96k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Data));
183
5.96k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
184
5.96k
    return E;
185
5.96k
  }));
186
187
  // Validate code section and expressions.
188
5.96k
  EXPECTED_TRY(validate(Mod.getCodeSection()).map_error([](auto E) {
189
4.39k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Code));
190
4.39k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
191
4.39k
    return E;
192
4.39k
  }));
193
194
  // Multiple tables are for the ReferenceTypes proposal.
195
4.39k
  if (Checker.getTables().size() > 1 &&
196
55
      !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
4.39k
  if (Checker.getMemories().size() > 1 &&
205
89
      !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
4.39k
  const_cast<AST::Module &>(Mod).setIsValidated();
214
4.39k
  return {};
215
4.39k
}
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.14k
    const auto &FType = CompType.getFuncType();
226
8.14k
    for (auto &PType : FType.getParamTypes()) {
227
6.65k
      EXPECTED_TRY(Checker.validate(PType).map_error([](auto E) {
228
6.65k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
229
6.65k
        return E;
230
6.65k
      }));
231
6.65k
    }
232
8.14k
    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.14k
    for (auto &RType : FType.getReturnTypes()) {
240
6.01k
      EXPECTED_TRY(Checker.validate(RType).map_error([](auto E) {
241
6.01k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
242
6.01k
        return E;
243
6.01k
      }));
244
6.01k
    }
245
8.14k
  } else {
246
459
    const auto &FTypes = CompType.getFieldTypes();
247
459
    for (auto &FieldType : FTypes) {
248
291
      EXPECTED_TRY(Checker.validate(FieldType.getStorageType()));
249
291
    }
250
459
  }
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
3
    spdlog::error(ErrCode::Value::InvalidSubType);
255
3
    spdlog::error("    Accepts only one super type currently."sv);
256
3
    return Unexpect(ErrCode::Value::InvalidSubType);
257
3
  }
258
259
8.58k
  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
22
      spdlog::error(ErrCode::Value::InvalidSubType);
287
22
      spdlog::error("    Super type not matched."sv);
288
22
      return Unexpect(ErrCode::Value::InvalidSubType);
289
22
    }
290
32
  }
291
8.54k
  return {};
292
8.58k
}
293
294
// Validate Limit type. See "include/validator/validator.h".
295
3.73k
Expect<void> Validator::validate(const AST::Limit &Lim) {
296
3.73k
  if (Lim.hasMax() && Lim.getMin() > Lim.getMax()) {
297
91
    spdlog::error(ErrCode::Value::InvalidLimit);
298
91
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
299
91
    return Unexpect(ErrCode::Value::InvalidLimit);
300
91
  }
301
3.64k
  if (Lim.isShared() && unlikely(!Lim.hasMax())) {
302
0
    spdlog::error(ErrCode::Value::SharedMemoryNoMax);
303
0
    return Unexpect(ErrCode::Value::SharedMemoryNoMax);
304
0
  }
305
3.64k
  return {};
306
3.64k
}
307
308
// Validate Table type. See "include/validator/validator.h".
309
1.33k
Expect<void> Validator::validate(const AST::TableType &Tab) {
310
  // Validate value type.
311
1.33k
  EXPECTED_TRY(Checker.validate(Tab.getRefType()));
312
  // Validate table limits.
313
1.29k
  const auto &Lim = Tab.getLimit();
314
1.29k
  EXPECTED_TRY(validate(Lim).map_error([](auto E) {
315
1.25k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
316
1.25k
    return E;
317
1.25k
  }));
318
1.25k
  uint64_t Range = getMaxAddress(Lim.getAddrType());
319
1.25k
  if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) {
320
    // Since spec test has no related error message, use this error instead.
321
131
    auto Code = Conf.hasProposal(Proposal::Memory64)
322
131
                    ? ErrCode::Value::InvalidTableSize64
323
131
                    : ErrCode::Value::InvalidLimit;
324
131
    spdlog::error(Code);
325
131
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
326
131
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
327
131
    return Unexpect(Code);
328
131
  }
329
1.12k
  return {};
330
1.25k
}
331
332
// Validate Memory type. See "include/validator/validator.h".
333
2.44k
Expect<void> Validator::validate(const AST::MemoryType &Mem) {
334
  // Validate memory limits.
335
2.44k
  const auto &Lim = Mem.getLimit();
336
2.44k
  EXPECTED_TRY(validate(Lim).map_error([](auto E) {
337
2.38k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
338
2.38k
    return E;
339
2.38k
  }));
340
2.38k
  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.38k
  uint64_t Range = Lim.is32() ? (static_cast<uint64_t>(1) << 16)
347
2.38k
                              : (static_cast<uint64_t>(1) << 48);
348
2.38k
  if (Lim.getMin() > Range || (Lim.hasMax() && Lim.getMax() > Range)) {
349
219
    auto Code = Conf.hasProposal(Proposal::Memory64)
350
219
                    ? ErrCode::Value::InvalidMemPages64
351
219
                    : ErrCode::Value::InvalidMemPages;
352
219
    spdlog::error(Code);
353
219
    spdlog::error(ErrInfo::InfoLimit(Lim.hasMax(), Lim.getMin(), Lim.getMax()));
354
219
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Limit));
355
219
    return Unexpect(Code);
356
219
  }
357
2.16k
  return {};
358
2.38k
}
359
360
// Validate Global type. See "include/validator/validator.h".
361
408
Expect<void> Validator::validate(const AST::GlobalType &Glob) {
362
  // Validate value type.
363
408
  return Checker.validate(Glob.getValType());
364
408
}
365
366
// Validate Table segment. See "include/validator/validator.h".
367
1.25k
Expect<void> Validator::validate(const AST::TableSegment &TabSeg) {
368
1.25k
  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
1.24k
  } else {
378
    // No init expression. Check that the reference type is nullable.
379
1.24k
    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
1.24k
  }
389
  // Validate table type.
390
1.24k
  return validate(TabSeg.getTableType()).map_error([](auto E) {
391
206
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table));
392
206
    return E;
393
206
  });
394
1.25k
}
395
396
// Validate Global segment. See "include/validator/validator.h".
397
657
Expect<void> Validator::validate(const AST::GlobalSegment &GlobSeg) {
398
  // Check global initialization is a const expression.
399
657
  EXPECTED_TRY(validateConstExpr(GlobSeg.getExpr().getInstrs(),
400
296
                                 {GlobSeg.getGlobalType().getValType()})
401
296
                   .map_error([](auto E) {
402
296
                     spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
403
296
                     return E;
404
296
                   }));
405
  // Validate global type.
406
296
  return validate(GlobSeg.getGlobalType()).map_error([](auto E) {
407
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global));
408
0
    return E;
409
0
  });
410
657
}
411
412
// Validate Element segment. See "include/validator/validator.h".
413
623
Expect<void> Validator::validate(const AST::ElementSegment &ElemSeg) {
414
  // Check that initialization expressions are const expressions.
415
1.36k
  for (auto &Expr : ElemSeg.getInitExprs()) {
416
1.36k
    EXPECTED_TRY(
417
1.36k
        validateConstExpr(Expr.getInstrs(), {ValType(ElemSeg.getRefType())})
418
1.36k
            .map_error([](auto E) {
419
1.36k
              spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
420
1.36k
              return E;
421
1.36k
            }));
422
1.36k
  }
423
424
  // The reference type should be valid.
425
541
  EXPECTED_TRY(Checker.validate(ElemSeg.getRefType()));
426
427
  // Passive and declarative cases are valid with a valid reference type.
428
539
  if (ElemSeg.getMode() == AST::ElementSegment::ElemMode::Active) {
429
    // Check table index and reference type in context.
430
310
    const auto &TableVec = Checker.getTables();
431
310
    if (ElemSeg.getIdx() >= TableVec.size()) {
432
41
      spdlog::error(ErrCode::Value::InvalidTableIdx);
433
41
      spdlog::error(ErrInfo::InfoForbidIndex(
434
41
          ErrInfo::IndexCategory::Table, ElemSeg.getIdx(),
435
41
          static_cast<uint32_t>(TableVec.size())));
436
41
      return Unexpect(ErrCode::Value::InvalidTableIdx);
437
41
    }
438
269
    if (!AST::TypeMatcher::matchType(Checker.getTypes(),
439
269
                                     TableVec[ElemSeg.getIdx()].second,
440
269
                                     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
261
    return validateConstExpr(ElemSeg.getExpr().getInstrs(),
449
261
                             {ValType(TableVec[ElemSeg.getIdx()].first)})
450
261
        .map_error([](auto E) {
451
4
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
452
4
          return E;
453
4
        });
454
269
  }
455
229
  return {};
456
539
}
457
458
// Validate Code segment. See "include/validator/validator.h".
459
Expect<void> Validator::validate(const AST::CodeSegment &CodeSeg,
460
12.7k
                                 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.7k
  const auto &FuncType =
464
12.7k
      Checker.getTypes()[TypeIdx]->getCompositeType().getFuncType();
465
  // Reset stack in FormChecker.
466
12.7k
  Checker.reset();
467
  // Add parameters to this frame.
468
12.7k
  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.7k
  for (auto Val : CodeSeg.getLocals()) {
474
209M
    for (uint32_t Cnt = 0; Cnt < Val.first; ++Cnt) {
475
      // The local value type should be valid.
476
209M
      EXPECTED_TRY(Checker.validate(Val.second));
477
209M
      Checker.addLocal(Val.second, false);
478
209M
    }
479
2.18k
  }
480
  // Validate function body expression.
481
12.7k
  return Checker
482
12.7k
      .validate(CodeSeg.getExpr().getInstrs(), FuncType.getReturnTypes())
483
12.7k
      .map_error([](auto E) {
484
1.57k
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
485
1.57k
        return E;
486
1.57k
      });
487
12.7k
}
488
489
// Validate Data segment. See "include/validator/validator.h".
490
799
Expect<void> Validator::validate(const AST::DataSegment &DataSeg) {
491
799
  switch (DataSeg.getMode()) {
492
217
  case AST::DataSegment::DataMode::Active: {
493
    // Check memory index in context.
494
217
    const auto &MemVec = Checker.getMemories();
495
217
    if (DataSeg.getIdx() >= MemVec.size()) {
496
27
      spdlog::error(ErrCode::Value::InvalidMemoryIdx);
497
27
      spdlog::error(ErrInfo::InfoForbidIndex(
498
27
          ErrInfo::IndexCategory::Memory, DataSeg.getIdx(),
499
27
          static_cast<uint32_t>(MemVec.size())));
500
27
      return Unexpect(ErrCode::Value::InvalidMemoryIdx);
501
27
    }
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
5
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
507
5
          return E;
508
5
        });
509
217
  }
510
582
  case AST::DataSegment::DataMode::Passive:
511
    // Passive case is always valid.
512
582
    return {};
513
0
  default:
514
0
    return {};
515
799
  }
516
799
}
517
518
// Validate Import description. See "include/validator/validator.h".
519
1.02k
Expect<void> Validator::validate(const AST::ImportDesc &ImpDesc) {
520
1.02k
  switch (ImpDesc.getExternalType()) {
521
  // External type and external content are ensured to match in the loader
522
  // phase.
523
516
  case ExternalType::Function: {
524
516
    const auto TId = ImpDesc.getExternalFuncTypeIdx();
525
    // Function type index must exist in context and be valid.
526
516
    if (TId >= Checker.getTypes().size()) {
527
19
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
528
19
      spdlog::error(ErrInfo::InfoForbidIndex(
529
19
          ErrInfo::IndexCategory::FunctionType, TId,
530
19
          static_cast<uint32_t>(Checker.getTypes().size())));
531
19
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
532
19
    }
533
497
    if (!Checker.getTypes()[TId]->getCompositeType().isFunc()) {
534
2
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
535
2
      spdlog::error("    Defined type index {} is not a function type."sv, TId);
536
2
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
537
2
    }
538
495
    Checker.addRef(static_cast<uint32_t>(Checker.getFunctions().size()));
539
495
    Checker.addFunc(TId, true);
540
495
    return {};
541
497
  }
542
89
  case ExternalType::Table: {
543
89
    const auto &TabType = ImpDesc.getExternalTableType();
544
    // Table type must be valid.
545
89
    EXPECTED_TRY(validate(TabType).map_error([](auto E) {
546
85
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Table));
547
85
      return E;
548
85
    }));
549
85
    Checker.addTable(TabType);
550
85
    return {};
551
89
  }
552
163
  case ExternalType::Memory: {
553
163
    const auto &MemType = ImpDesc.getExternalMemoryType();
554
    // Memory type must be valid.
555
163
    EXPECTED_TRY(validate(MemType).map_error([](auto E) {
556
159
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory));
557
159
      return E;
558
159
    }));
559
159
    Checker.addMemory(MemType);
560
159
    return {};
561
163
  }
562
140
  case ExternalType::Tag: {
563
140
    const auto &T = ImpDesc.getExternalTagType();
564
    // Tag type index must exist in context.
565
140
    auto TagTypeIdx = T.getTypeIdx();
566
140
    if (TagTypeIdx >= Checker.getTypes().size()) {
567
29
      spdlog::error(ErrCode::Value::InvalidTagIdx);
568
29
      spdlog::error(ErrInfo::InfoForbidIndex(
569
29
          ErrInfo::IndexCategory::TagType, TagTypeIdx,
570
29
          static_cast<uint32_t>(Checker.getTypes().size())));
571
29
      return Unexpect(ErrCode::Value::InvalidTagIdx);
572
29
    }
573
    // Tag type must be valid.
574
111
    auto &CompType = Checker.getTypes()[TagTypeIdx]->getCompositeType();
575
111
    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
109
    if (!CompType.getFuncType().getReturnTypes().empty()) {
582
2
      spdlog::error(ErrCode::Value::InvalidTagResultType);
583
2
      return Unexpect(ErrCode::Value::InvalidTagResultType);
584
2
    }
585
107
    Checker.addTag(TagTypeIdx);
586
107
    return {};
587
109
  }
588
112
  case ExternalType::Global: {
589
112
    const auto &GlobType = ImpDesc.getExternalGlobalType();
590
    // Global type must be valid.
591
112
    EXPECTED_TRY(validate(GlobType).map_error([](auto E) {
592
108
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Global));
593
108
      return E;
594
108
    }));
595
108
    Checker.addGlobal(GlobType, true);
596
108
    return {};
597
112
  }
598
0
  default:
599
0
    return {};
600
1.02k
  }
601
1.02k
}
602
603
// Validate Export description. See "include/validator/validator.h".
604
10.6k
Expect<void> Validator::validate(const AST::ExportDesc &ExpDesc) {
605
10.6k
  auto Id = ExpDesc.getExternalIndex();
606
10.6k
  switch (ExpDesc.getExternalType()) {
607
10.2k
  case ExternalType::Function:
608
10.2k
    if (Id >= Checker.getFunctions().size()) {
609
51
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
610
51
      spdlog::error(ErrInfo::InfoForbidIndex(
611
51
          ErrInfo::IndexCategory::Function, Id,
612
51
          static_cast<uint32_t>(Checker.getFunctions().size())));
613
51
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
614
51
    }
615
10.1k
    Checker.addRef(Id);
616
10.1k
    return {};
617
60
  case ExternalType::Table:
618
60
    if (Id >= Checker.getTables().size()) {
619
29
      spdlog::error(ErrCode::Value::InvalidTableIdx);
620
29
      spdlog::error(ErrInfo::InfoForbidIndex(
621
29
          ErrInfo::IndexCategory::Table, Id,
622
29
          static_cast<uint32_t>(Checker.getTables().size())));
623
29
      return Unexpect(ErrCode::Value::InvalidTableIdx);
624
29
    }
625
31
    return {};
626
155
  case ExternalType::Memory:
627
155
    if (Id >= Checker.getMemories().size()) {
628
49
      spdlog::error(ErrCode::Value::InvalidMemoryIdx);
629
49
      spdlog::error(ErrInfo::InfoForbidIndex(
630
49
          ErrInfo::IndexCategory::Memory, Id,
631
49
          static_cast<uint32_t>(Checker.getMemories().size())));
632
49
      return Unexpect(ErrCode::Value::InvalidMemoryIdx);
633
49
    }
634
106
    return {};
635
41
  case ExternalType::Tag:
636
41
    if (Id >= Checker.getTags().size()) {
637
27
      spdlog::error(ErrCode::Value::InvalidTagIdx);
638
27
      spdlog::error(ErrInfo::InfoForbidIndex(
639
27
          ErrInfo::IndexCategory::Tag, Id,
640
27
          static_cast<uint32_t>(Checker.getTags().size())));
641
27
      return Unexpect(ErrCode::Value::InvalidTagIdx);
642
27
    }
643
14
    return {};
644
133
  case ExternalType::Global:
645
133
    if (Id >= Checker.getGlobals().size()) {
646
10
      spdlog::error(ErrCode::Value::InvalidGlobalIdx);
647
10
      spdlog::error(ErrInfo::InfoForbidIndex(
648
10
          ErrInfo::IndexCategory::Global, Id,
649
10
          static_cast<uint32_t>(Checker.getGlobals().size())));
650
10
      return Unexpect(ErrCode::Value::InvalidGlobalIdx);
651
10
    }
652
123
    return {};
653
0
  default:
654
0
    return {};
655
10.6k
  }
656
10.6k
}
657
658
7.41k
Expect<void> Validator::validate(const AST::TypeSection &TypeSec) {
659
7.41k
  const auto STypeList = TypeSec.getContent();
660
7.41k
  std::vector<uint32_t> SubTypeDepthMap(STypeList.size(), Unvisited);
661
7.41k
  uint32_t Idx = 0;
662
15.9k
  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
7.35k
  return {};
693
7.41k
}
694
695
// Validate Import section. See "include/validator/validator.h".
696
7.35k
Expect<void> Validator::validate(const AST::ImportSection &ImportSec) {
697
7.35k
  for (auto &ImportDesc : ImportSec.getContent()) {
698
1.02k
    EXPECTED_TRY(validate(ImportDesc).map_error([](auto E) {
699
1.02k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Import));
700
1.02k
      return E;
701
1.02k
    }));
702
1.02k
  }
703
7.28k
  return {};
704
7.35k
}
705
706
// Validate Function section. See "include/validator/validator.h".
707
7.28k
Expect<void> Validator::validate(const AST::FunctionSection &FuncSec) {
708
7.28k
  const auto &FuncVec = FuncSec.getContent();
709
7.28k
  const auto &TypeVec = Checker.getTypes();
710
711
  // Check whether the function type ID is valid in context.
712
17.5k
  for (auto &TId : FuncVec) {
713
17.5k
    if (TId >= TypeVec.size()) {
714
14
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
715
14
      spdlog::error(
716
14
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::FunctionType, TId,
717
14
                                   static_cast<uint32_t>(TypeVec.size())));
718
14
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
719
14
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
720
14
    }
721
17.5k
    if (!TypeVec[TId]->getCompositeType().isFunc()) {
722
2
      spdlog::error(ErrCode::Value::InvalidFuncTypeIdx);
723
2
      spdlog::error("    Defined type index {} is not a function type."sv, TId);
724
2
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function));
725
2
      return Unexpect(ErrCode::Value::InvalidFuncTypeIdx);
726
2
    }
727
17.5k
    Checker.addFunc(TId);
728
17.5k
  }
729
7.27k
  return {};
730
7.28k
}
731
732
// Validate Table section. See "include/validator/validator.h".
733
7.27k
Expect<void> Validator::validate(const AST::TableSection &TabSec) {
734
7.27k
  for (auto &Tab : TabSec.getContent()) {
735
1.25k
    EXPECTED_TRY(validate(Tab).map_error([](auto E) {
736
1.04k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table));
737
1.04k
      return E;
738
1.04k
    }));
739
1.04k
    Checker.addTable(Tab.getTableType());
740
1.04k
  }
741
7.05k
  return {};
742
7.27k
}
743
744
// Validate Memory section. See "include/validator/validator.h".
745
7.05k
Expect<void> Validator::validate(const AST::MemorySection &MemSec) {
746
7.05k
  for (auto &Mem : MemSec.getContent()) {
747
2.27k
    EXPECTED_TRY(validate(Mem).map_error([](auto E) {
748
2.00k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Memory));
749
2.00k
      return E;
750
2.00k
    }));
751
2.00k
    Checker.addMemory(Mem);
752
2.00k
  }
753
6.78k
  return {};
754
7.05k
}
755
756
// Validate Global section. See "include/validator/validator.h".
757
6.78k
Expect<void> Validator::validate(const AST::GlobalSection &GlobSec) {
758
6.78k
  for (auto &GlobSeg : GlobSec.getContent()) {
759
657
    EXPECTED_TRY(validate(GlobSeg).map_error([](auto E) {
760
296
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global));
761
296
      return E;
762
296
    }));
763
296
    Checker.addGlobal(GlobSeg.getGlobalType());
764
296
  }
765
6.42k
  return {};
766
6.78k
}
767
768
// Validate Element section. See "include/validator/validator.h".
769
6.13k
Expect<void> Validator::validate(const AST::ElementSection &ElemSec) {
770
6.13k
  for (auto &ElemSeg : ElemSec.getContent()) {
771
623
    EXPECTED_TRY(validate(ElemSeg).map_error([](auto E) {
772
486
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element));
773
486
      return E;
774
486
    }));
775
486
    Checker.addElem(ElemSeg);
776
486
  }
777
5.99k
  return {};
778
6.13k
}
779
780
// Validate Code section. See "include/validator/validator.h".
781
5.96k
Expect<void> Validator::validate(const AST::CodeSection &CodeSec) {
782
5.96k
  const auto &CodeVec = CodeSec.getContent();
783
5.96k
  const auto &FuncVec = Checker.getFunctions();
784
785
  // Validate function body.
786
17.1k
  for (uint32_t Id = 0; Id < static_cast<uint32_t>(CodeVec.size()); ++Id) {
787
    // Added functions contain imported functions.
788
12.7k
    uint32_t TId = Id + static_cast<uint32_t>(Checker.getNumImportFuncs());
789
12.7k
    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.7k
    EXPECTED_TRY(validate(CodeVec[Id], FuncVec[TId]).map_error([](auto E) {
797
12.7k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Code));
798
12.7k
      return E;
799
12.7k
    }));
800
12.7k
  }
801
4.39k
  return {};
802
5.96k
}
803
804
// Validate Data section. See "include/validator/validator.h".
805
5.99k
Expect<void> Validator::validate(const AST::DataSection &DataSec) {
806
5.99k
  for (auto &DataSeg : DataSec.getContent()) {
807
799
    EXPECTED_TRY(validate(DataSeg).map_error([](auto E) {
808
767
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data));
809
767
      return E;
810
767
    }));
811
767
    Checker.addData(DataSeg);
812
767
  }
813
5.96k
  return {};
814
5.99k
}
815
816
// Validate Start section. See "include/validator/validator.h".
817
6.20k
Expect<void> Validator::validate(const AST::StartSection &StartSec) {
818
6.20k
  if (StartSec.getContent()) {
819
71
    auto FId = *StartSec.getContent();
820
71
    if (FId >= Checker.getFunctions().size()) {
821
62
      spdlog::error(ErrCode::Value::InvalidFuncIdx);
822
62
      spdlog::error(ErrInfo::InfoForbidIndex(
823
62
          ErrInfo::IndexCategory::Function, FId,
824
62
          static_cast<uint32_t>(Checker.getFunctions().size())));
825
62
      return Unexpect(ErrCode::Value::InvalidFuncIdx);
826
62
    }
827
9
    auto TId = Checker.getFunctions()[FId];
828
9
    assuming(TId < Checker.getTypes().size());
829
9
    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
9
    auto &Type = Checker.getTypes()[TId]->getCompositeType().getFuncType();
835
9
    if (Type.getParamTypes().size() != 0 || Type.getReturnTypes().size() != 0) {
836
      // Start function signature should be {}->{}
837
4
      spdlog::error(ErrCode::Value::InvalidStartFunc);
838
4
      spdlog::error(ErrInfo::InfoMismatch({}, {}, Type.getParamTypes(),
839
4
                                          Type.getReturnTypes()));
840
4
      return Unexpect(ErrCode::Value::InvalidStartFunc);
841
4
    }
842
9
  }
843
6.13k
  return {};
844
6.20k
}
845
846
// Validate Export section. See "include/validator/validator.h".
847
6.37k
Expect<void> Validator::validate(const AST::ExportSection &ExportSec) {
848
6.37k
  std::unordered_set<std::string_view, Hash::Hash> ExportNames;
849
10.6k
  for (auto &ExportDesc : ExportSec.getContent()) {
850
10.6k
    auto Result = ExportNames.emplace(ExportDesc.getExternalName());
851
10.6k
    if (!Result.second) {
852
      // Duplicated export name.
853
7
      spdlog::error(ErrCode::Value::DupExportName);
854
7
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export));
855
7
      return Unexpect(ErrCode::Value::DupExportName);
856
7
    }
857
10.6k
    EXPECTED_TRY(validate(ExportDesc).map_error([](auto E) {
858
10.6k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Export));
859
10.6k
      return E;
860
10.6k
    }));
861
10.6k
  }
862
6.20k
  return {};
863
6.37k
}
864
865
// Validate Tag section. See "include/validator/validator.h".
866
6.42k
Expect<void> Validator::validate(const AST::TagSection &TagSec) {
867
6.42k
  const auto &TagVec = TagSec.getContent();
868
6.42k
  const auto &TypeVec = Checker.getTypes();
869
870
  // Check whether the tag type ID is valid in context.
871
6.42k
  for (auto &TagType : TagVec) {
872
166
    auto TagTypeIdx = TagType.getTypeIdx();
873
166
    if (TagTypeIdx >= TypeVec.size()) {
874
46
      spdlog::error(ErrCode::Value::InvalidTagIdx);
875
46
      spdlog::error(
876
46
          ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::TagType, TagTypeIdx,
877
46
                                   static_cast<uint32_t>(TypeVec.size())));
878
46
      return Unexpect(ErrCode::Value::InvalidTagIdx);
879
46
    }
880
120
    auto &CompType = TypeVec[TagTypeIdx]->getCompositeType();
881
120
    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
118
    if (!CompType.getFuncType().getReturnTypes().empty()) {
888
2
      spdlog::error(ErrCode::Value::InvalidTagResultType);
889
2
      return Unexpect(ErrCode::Value::InvalidTagResultType);
890
2
    }
891
116
    Checker.addTag(TagTypeIdx);
892
116
  }
893
6.37k
  return {};
894
6.42k
}
895
896
// Validate constant expression. See "include/validator/validator.h".
897
Expect<void> Validator::validateConstExpr(AST::InstrView Instrs,
898
2.48k
                                          Span<const ValType> Returns) {
899
8.38k
  for (auto &Instr : Instrs) {
900
    // Only these instructions are accepted.
901
8.38k
    switch (Instr.getOpCode()) {
902
63
    case OpCode::Global__get: {
903
      // For the initialization case, global indices must be imported globals.
904
63
      auto GlobIdx = Instr.getTargetIndex();
905
63
      uint32_t ValidGlobalSize = Checker.getNumImportGlobals();
906
63
      if (Conf.hasProposal(Proposal::FunctionReferences)) {
907
63
        ValidGlobalSize = static_cast<uint32_t>(Checker.getGlobals().size());
908
63
      }
909
63
      if (GlobIdx >= ValidGlobalSize) {
910
46
        spdlog::error(ErrCode::Value::InvalidGlobalIdx);
911
46
        spdlog::error(ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Global,
912
46
                                               GlobIdx, ValidGlobalSize));
913
46
        spdlog::error(
914
46
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
915
46
        return Unexpect(ErrCode::Value::InvalidGlobalIdx);
916
46
      }
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.26k
    case OpCode::Ref__func: {
926
      // In a const expression, add the reference to the context.
927
1.26k
      auto FuncIdx = Instr.getTargetIndex();
928
1.26k
      if (FuncIdx >= Checker.getFunctions().size()) {
929
        // Function index out of range.
930
45
        spdlog::error(ErrCode::Value::InvalidFuncIdx);
931
45
        spdlog::error(ErrInfo::InfoForbidIndex(
932
45
            ErrInfo::IndexCategory::Function, FuncIdx,
933
45
            static_cast<uint32_t>(Checker.getFunctions().size())));
934
45
        spdlog::error(
935
45
            ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
936
45
        return Unexpect(ErrCode::Value::InvalidFuncIdx);
937
45
      }
938
1.22k
      Checker.addRef(Instr.getTargetIndex());
939
1.22k
      break;
940
1.26k
    }
941
1.48k
    case OpCode::I32__const:
942
1.97k
    case OpCode::I64__const:
943
2.07k
    case OpCode::F32__const:
944
2.15k
    case OpCode::F64__const:
945
2.40k
    case OpCode::Ref__null:
946
2.44k
    case OpCode::V128__const:
947
4.72k
    case OpCode::End:
948
4.80k
    case OpCode::Struct__new:
949
4.87k
    case OpCode::Struct__new_default:
950
4.89k
    case OpCode::Array__new:
951
4.96k
    case OpCode::Array__new_default:
952
4.99k
    case OpCode::Array__new_fixed:
953
5.05k
    case OpCode::Any__convert_extern:
954
5.13k
    case OpCode::Extern__convert_any:
955
5.22k
    case OpCode::Ref__i31:
956
5.22k
      break;
957
958
    // For the Extended-const proposal, these instructions are accepted.
959
206
    case OpCode::I32__add:
960
479
    case OpCode::I32__sub:
961
848
    case OpCode::I32__mul:
962
1.15k
    case OpCode::I64__add:
963
1.44k
    case OpCode::I64__sub:
964
1.72k
    case OpCode::I64__mul:
965
1.72k
      if (Conf.hasProposal(Proposal::ExtendedConst)) {
966
1.72k
        break;
967
1.72k
      }
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
104
    default:
975
104
      spdlog::error(ErrCode::Value::ConstExprRequired);
976
104
      spdlog::error(
977
104
          ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset()));
978
104
      return Unexpect(ErrCode::Value::ConstExprRequired);
979
8.38k
    }
980
8.38k
  }
981
  // Validate expression with result types.
982
2.28k
  Checker.reset();
983
2.28k
  return Checker.validate(Instrs, Returns);
984
2.48k
}
985
986
} // namespace Validator
987
} // namespace WasmEdge