Coverage Report

Created: 2025-12-31 06:34

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