Coverage Report

Created: 2025-07-01 06:18

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