Coverage Report

Created: 2026-09-28 06:22

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