Coverage Report

Created: 2025-12-14 06:36

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