Coverage Report

Created: 2025-10-10 06:52

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