Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/include/validator/validator_component.h
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
#pragma once
4
5
#include "common/errinfo.h"
6
#include "validator/context.h"
7
#include "validator/validator.h"
8
9
namespace WasmEdge {
10
namespace Validator {
11
12
using namespace std::literals;
13
using namespace AST::Component;
14
15
// Helper func for better logging
16
0
inline std::string toString(const SortCase &SC) {
17
0
  switch (SC) {
18
0
  case SortCase::Func:
19
0
    return "Func";
20
0
  case SortCase::Value:
21
0
    return "Value";
22
0
  case SortCase::Type:
23
0
    return "Type";
24
0
  case SortCase::Component:
25
0
    return "Component";
26
0
  case SortCase::Instance:
27
0
    return "Instance";
28
0
  default:
29
0
    return "Unknown SortCase";
30
0
  }
31
0
}
32
33
0
inline std::string toString(const CoreSort &CS) {
34
0
  switch (CS) {
35
0
  case CoreSort::Func:
36
0
    return "Func";
37
0
  case CoreSort::Table:
38
0
    return "Table";
39
0
  case CoreSort::Memory:
40
0
    return "Memory";
41
0
  case CoreSort::Global:
42
0
    return "Global";
43
0
  case CoreSort::Type:
44
0
    return "Type";
45
0
  case CoreSort::Module:
46
0
    return "Module";
47
0
  case CoreSort::Instance:
48
0
    return "Instance";
49
0
  default:
50
0
    return "Unknown CoreSort";
51
0
  }
52
0
}
53
54
0
inline std::string toString(const Sort &S) {
55
0
  return std::visit(
56
0
      [](const auto &value) -> std::string { return toString(value); }, S);
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > WasmEdge::Validator::toString(std::__1::variant<WasmEdge::AST::Component::CoreSort, WasmEdge::AST::Component::SortCase> const&)::{lambda(auto:1 const&)#1}::operator()<WasmEdge::AST::Component::CoreSort>(WasmEdge::AST::Component::CoreSort const&) const
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > WasmEdge::Validator::toString(std::__1::variant<WasmEdge::AST::Component::CoreSort, WasmEdge::AST::Component::SortCase> const&)::{lambda(auto:1 const&)#1}::operator()<WasmEdge::AST::Component::SortCase>(WasmEdge::AST::Component::SortCase const&) const
57
0
}
58
59
0
inline std::string toString(const IndexKind &IK) {
60
0
  switch (IK) {
61
0
  case IndexKind::CoreType:
62
0
    return "CoreType";
63
0
  case IndexKind::FuncType:
64
0
    return "FuncType";
65
0
  case IndexKind::ComponentType:
66
0
    return "ComponentType";
67
0
  case IndexKind::InstanceType:
68
0
    return "InstanceType";
69
0
  default:
70
0
    return "Unknown IndexKind (" + std::to_string(static_cast<int>(IK)) + ")";
71
0
  }
72
0
}
73
74
struct ExternDescVisitor {
75
0
  ExternDescVisitor(Context &Ctx) : Ctx(Ctx) {}
76
77
0
  Expect<void> operator()(const DescTypeIndex &DTI) {
78
0
    auto Idx = DTI.getIndex();
79
0
    switch (DTI.getKind()) {
80
0
    case IndexKind::CoreType:
81
0
      Ctx.incCoreIndexSize(CoreSort::Type);
82
0
      break;
83
0
    case IndexKind::FuncType:
84
0
      Ctx.incComponentIndexSize(SortCase::Func);
85
0
      break;
86
0
    case IndexKind::ComponentType:
87
0
      Ctx.incComponentIndexSize(SortCase::Component);
88
0
      break;
89
0
    case IndexKind::InstanceType:
90
0
      Ctx.incComponentIndexSize(SortCase::Instance);
91
0
      const auto *IT = Ctx.getComponentInstanceType(Idx);
92
0
      if (IT != nullptr) {
93
0
        const auto &InstanceDecls = IT->getContent();
94
0
        for (auto &InstanceDecl : InstanceDecls) {
95
0
          if (std::holds_alternative<CoreType>(InstanceDecl)) {
96
0
            spdlog::debug("Core Type found"sv);
97
0
          } else if (std::holds_alternative<std::shared_ptr<Type>>(
98
0
                         InstanceDecl)) {
99
0
            spdlog::debug("Def Type found"sv);
100
0
          } else if (std::holds_alternative<Alias>(InstanceDecl)) {
101
0
            spdlog::debug("Alias found"sv);
102
0
          } else if (std::holds_alternative<ExportDecl>(InstanceDecl)) {
103
0
            auto &ED = std::get<ExportDecl>(InstanceDecl);
104
0
            uint32_t InstanceIdx = static_cast<uint32_t>(
105
0
                Ctx.getComponentIndexSize(SortCase::Instance) - 1);
106
0
            Ctx.addComponentInstanceExport(InstanceIdx, ED.getExportName(),
107
0
                                           ED.getExternDesc());
108
0
            spdlog::debug("Export Decl found"sv);
109
0
          } else {
110
0
            assumingUnreachable();
111
0
          }
112
0
        }
113
0
      } else {
114
0
        assumingUnreachable();
115
0
      }
116
0
      break;
117
0
    }
118
0
    return {};
119
0
  }
120
0
  Expect<void> operator()(const TypeBound &) {
121
    // TypeBound == std::optional<TypeIndex>
122
0
    Ctx.incComponentIndexSize(SortCase::Type);
123
0
    return {};
124
0
  }
125
0
  Expect<void> operator()(const ValueType &) {
126
0
    Ctx.incComponentIndexSize(SortCase::Type);
127
0
    return {};
128
0
  }
129
130
private:
131
  Context &Ctx;
132
};
133
134
struct CoreInstanceExprVisitor {
135
0
  CoreInstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
136
137
0
  Expect<void> operator()(const CoreInstantiate &Inst) {
138
0
    const uint32_t ModuleIdx = Inst.getModuleIdx();
139
0
    if (ModuleIdx >= Ctx.getCoreModuleCount()) {
140
0
      spdlog::error(ErrCode::Value::InvalidIndex);
141
0
      spdlog::error(
142
0
          "CoreInstanceSection: Module index {} exceeds available core modules {}"sv,
143
0
          ModuleIdx, Ctx.getCoreModuleCount());
144
0
      return Unexpect(ErrCode::Value::InvalidIndex);
145
0
    }
146
0
    auto Args = Inst.getArgs();
147
0
    auto ImportsList = getImports(Inst);
148
0
    for (auto Import : ImportsList) {
149
0
      auto ArgIt = std::find_if(Args.begin(), Args.end(), [&](const auto &Arg) {
150
0
        return Arg.getName() == Import;
151
0
      });
152
153
0
      if (ArgIt == Args.end()) {
154
0
        spdlog::error(ErrCode::Value::MissingArgument);
155
0
        spdlog::error("Module[{}]: Missing argument for import '{}'"sv,
156
0
                      Inst.getModuleIdx(), Import);
157
0
        return Unexpect(ErrCode::Value::MissingArgument);
158
0
      }
159
0
    }
160
0
    Ctx.incCoreIndexSize(CoreSort::Instance);
161
0
    const auto &Mod = Ctx.getCoreModule(ModuleIdx);
162
0
    const auto &ExportDescs = Mod.getExportSection().getContent();
163
0
    uint32_t InstanceIdx =
164
0
        static_cast<uint32_t>(Ctx.getCoreIndexSize(CoreSort::Instance) - 1);
165
0
    for (const auto &ExportDesc : ExportDescs) {
166
0
      Ctx.addCoreInstanceExport(InstanceIdx, ExportDesc.getExternalName(),
167
0
                                ExportDesc.getExternalType());
168
0
    }
169
0
    return {};
170
0
  }
171
172
0
  Expect<void> operator()(const CoreInlineExports &Exports) {
173
0
    for (const auto &Export : Exports.getExports()) {
174
0
      auto ExportName = Export.getName();
175
0
      auto SortIdx = Export.getSortIdx();
176
0
      auto Sort = SortIdx.getSort();
177
0
      uint32_t Idx = SortIdx.getSortIdx();
178
179
0
      if (!isValidArgumentIndex(Sort, Idx)) {
180
0
        spdlog::error(ErrCode::Value::InvalidIndex);
181
0
        spdlog::error("Core: Inline export '{}' refers to invalid index {}"sv,
182
0
                      ExportName, Idx);
183
0
        return Unexpect(ErrCode::Value::InvalidIndex);
184
0
      }
185
0
    }
186
0
    Ctx.incCoreIndexSize(CoreSort::Instance);
187
0
    return {};
188
0
  }
189
190
private:
191
  Context &Ctx;
192
193
0
  std::vector<std::string> getImports(const CoreInstantiate &Inst) {
194
0
    const uint32_t Index = Inst.getModuleIdx();
195
0
    std::vector<std::string> ImportsList;
196
197
0
    const auto &Mod = Ctx.getCoreModule(Index);
198
0
    const auto &ImportDesc = Mod.getImportSection().getContent();
199
200
0
    for (const auto &Import : ImportDesc) {
201
0
      ImportsList.emplace_back(std::string(Import.getModuleName()));
202
0
    }
203
0
    return ImportsList;
204
0
  }
205
206
0
  bool isValidArgumentIndex(const CoreSort &ArgSort, const uint32_t Idx) {
207
0
    if (Ctx.getCoreIndexSize(ArgSort) > Idx) {
208
0
      return true;
209
0
    }
210
0
    return false;
211
0
  }
212
};
213
214
struct InstanceExprVisitor {
215
0
  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
216
217
0
  Expect<void> operator()(const Instantiate &Inst) {
218
0
    auto Args = Inst.getArgs();
219
0
    auto ImportMap = getImports(Inst.getComponentIdx());
220
221
0
    for (auto It = ImportMap.begin(); It != ImportMap.end(); ++It) {
222
0
      const auto &ImportName = It->first;
223
0
      const auto &ImportDesc = It->second;
224
0
      auto ArgIt = std::find_if(Args.begin(), Args.end(), [&](const auto &Arg) {
225
0
        return Arg.getName() == ImportName;
226
0
      });
227
228
0
      if (ArgIt == Args.end()) {
229
0
        spdlog::error(ErrCode::Value::MissingArgument);
230
0
        spdlog::error("Component[{}]: Missing argument for import '{}'"sv,
231
0
                      Inst.getComponentIdx(), ImportName);
232
0
        return Unexpect(ErrCode::Value::MissingArgument);
233
0
      }
234
235
0
      const auto &ArgSortIndex = ArgIt->getIndex();
236
0
      const auto &ArgSort = ArgSortIndex.getSort();
237
0
      const uint32_t ArgIdx = ArgSortIndex.getSortIdx();
238
239
0
      if (!matchImportAndArgTypes(ImportDesc, ArgSort)) {
240
0
        spdlog::error(ErrCode::Value::ArgTypeMismatch);
241
0
        spdlog::error("Component[{}]: Argument '{}' type mismatch"sv,
242
0
                      Inst.getComponentIdx(), ImportName);
243
0
        return Unexpect(ErrCode::Value::ArgTypeMismatch);
244
0
      }
245
246
0
      if (!isValidArgumentIndex(ArgSort, ArgIdx)) {
247
0
        spdlog::error(ErrCode::Value::InvalidIndex);
248
0
        spdlog::error(
249
0
            "Component[{}]: Argument '{}' refers to invalid index {}"sv,
250
0
            Inst.getComponentIdx(), ArgIt->getName(), ArgIdx);
251
0
        return Unexpect(ErrCode::Value::InvalidIndex);
252
0
      }
253
254
0
      if (std::holds_alternative<SortCase>(ArgSort) &&
255
0
          std::get<SortCase>(ArgSort) == SortCase::Type &&
256
0
          std::holds_alternative<TypeBound>(ImportDesc)) {
257
0
        Ctx.substituteTypeImport(ImportName, ArgIdx);
258
0
      }
259
0
    }
260
0
    Ctx.incComponentIndexSize(SortCase::Instance);
261
0
    return {};
262
0
  }
263
0
  Expect<void> operator()(const InlineExports &Exports) {
264
0
    for (const auto &Export : Exports.getExports()) {
265
0
      auto ExportName = Export.getName();
266
0
      auto SortIdx = Export.getSortIdx();
267
0
      auto Sort = SortIdx.getSort();
268
0
      uint32_t Idx = SortIdx.getSortIdx();
269
270
0
      if (!isValidArgumentIndex(Sort, Idx)) {
271
0
        spdlog::error(ErrCode::Value::InvalidIndex);
272
0
        spdlog::error(
273
0
            "Component: Inline export '{}' refers to invalid index {}"sv,
274
0
            ExportName, Idx);
275
0
        return Unexpect(ErrCode::Value::InvalidIndex);
276
0
      }
277
278
0
      if (std::holds_alternative<SortCase>(Sort) &&
279
0
          std::get<SortCase>(Sort) == SortCase::Type) {
280
0
        auto SubstitutedIdx = Ctx.getSubstitutedType(std::string(ExportName));
281
0
        if (SubstitutedIdx.has_value() && Idx != SubstitutedIdx.value()) {
282
0
          spdlog::error(ErrCode::Value::InvalidTypeReference);
283
0
          spdlog::error(
284
0
              "Component: Inline export '{}' type index {} does not match substituted type index {}"sv,
285
0
              ExportName, Idx, SubstitutedIdx.value());
286
0
          return Unexpect(ErrCode::Value::InvalidTypeReference);
287
0
        }
288
0
      }
289
0
    }
290
0
    Ctx.incComponentIndexSize(SortCase::Instance);
291
0
    return {};
292
0
  }
293
294
private:
295
  Context &Ctx;
296
297
0
  std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) {
298
0
    std::unordered_map<std::string, ExternDesc> ImportMap;
299
300
0
    if (Index >= Ctx.getComponentCount()) {
301
0
      spdlog::error("Unreachable State: Index {} exceeds Component Count {}"sv,
302
0
                    Index, Ctx.getComponentCount());
303
0
      spdlog::error(WasmEdge::ErrInfo::InfoBoundary(
304
0
          Index, 0, static_cast<uint32_t>(Ctx.getComponentCount())));
305
306
0
      return ImportMap;
307
0
    }
308
309
0
    auto &Comp = Ctx.getComponent(Index);
310
311
0
    for (const auto &Sec : Comp.getSections()) {
312
0
      if (std::holds_alternative<ImportSection>(Sec)) {
313
0
        const auto &ImportSec = std::get<ImportSection>(Sec);
314
315
0
        for (const auto &Import : ImportSec.getContent()) {
316
0
          ImportMap[std::string(Import.getName())] = Import.getDesc();
317
0
        }
318
0
      }
319
0
    }
320
321
0
    return ImportMap;
322
0
  }
323
324
  // https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md
325
  bool matchImportAndArgTypes(const ExternDesc &ImportType,
326
0
                              const Sort &ArgSort) {
327
0
    if (std::holds_alternative<CoreSort>(ArgSort)) {
328
0
      CoreSort ArgCoreSort = std::get<CoreSort>(ArgSort);
329
330
0
      if (std::holds_alternative<DescTypeIndex>(ImportType)) {
331
0
        const auto &Desc = std::get<DescTypeIndex>(ImportType);
332
0
        IndexKind Kind = Desc.getKind();
333
334
0
        if ((Kind == IndexKind::CoreType && ArgCoreSort == CoreSort::Type) ||
335
0
            (Kind == IndexKind::FuncType && ArgCoreSort == CoreSort::Func) ||
336
0
            (Kind == IndexKind::ComponentType &&
337
0
             ArgCoreSort == CoreSort::Module) ||
338
0
            (Kind == IndexKind::InstanceType &&
339
0
             ArgCoreSort == CoreSort::Instance)) {
340
0
          return true;
341
0
        }
342
0
        spdlog::error("[Core Sort] Type mismatch: Expected '{}' but got '{}'"sv,
343
0
                      WasmEdge::Validator::toString(Kind),
344
0
                      WasmEdge::Validator::toString(ArgCoreSort));
345
346
0
        return false;
347
0
      } else if (std::holds_alternative<ValueType>(ImportType)) {
348
0
        if (ArgCoreSort == CoreSort::Func || ArgCoreSort == CoreSort::Table ||
349
0
            ArgCoreSort == CoreSort::Memory ||
350
0
            ArgCoreSort == CoreSort::Global) {
351
0
          return true;
352
0
        }
353
0
        spdlog::error(
354
0
            "[Core Sort] Type mismatch: Expected 'Func', 'Table', 'Memory', or 'Global' but got '{}'"sv,
355
0
            WasmEdge::Validator::toString(ArgCoreSort));
356
0
        return false;
357
0
      } else if (std::holds_alternative<TypeBound>(ImportType)) {
358
0
        if (ArgCoreSort == CoreSort::Module ||
359
0
            ArgCoreSort == CoreSort::Instance) {
360
0
          return true;
361
0
        }
362
0
        spdlog::error(
363
0
            "[Core Sort] Type mismatch: Expected 'Module' or 'Instance' but got '{}'"sv,
364
0
            WasmEdge::Validator::toString(ArgCoreSort));
365
0
        return false;
366
0
      }
367
0
    } else if (std::holds_alternative<SortCase>(ArgSort)) {
368
0
      SortCase ArgSortCase = std::get<SortCase>(ArgSort);
369
370
0
      if (std::holds_alternative<TypeBound>(ImportType)) {
371
0
        if (ArgSortCase == SortCase::Type) {
372
0
          return true;
373
0
        }
374
0
        spdlog::error(
375
0
            "[Sort Case] Type mismatch: Expected 'Type' but got '{}'"sv,
376
0
            WasmEdge::Validator::toString(ArgSortCase));
377
0
        return false;
378
0
      } else if (std::holds_alternative<ValueType>(ImportType)) {
379
0
        if (ArgSortCase == SortCase::Value) {
380
0
          return true;
381
0
        }
382
0
        spdlog::error(
383
0
            "[Sort Case] Type mismatch: Expected 'Value' but got '{}'"sv,
384
0
            WasmEdge::Validator::toString(ArgSortCase));
385
0
        return false;
386
0
      } else if (std::holds_alternative<DescTypeIndex>(ImportType)) {
387
0
        const auto &Desc = std::get<DescTypeIndex>(ImportType);
388
0
        IndexKind Kind = Desc.getKind();
389
390
0
        if ((Kind == IndexKind::ComponentType &&
391
0
             ArgSortCase == SortCase::Component) ||
392
0
            (Kind == IndexKind::InstanceType &&
393
0
             ArgSortCase == SortCase::Instance) ||
394
0
            (Kind == IndexKind::FuncType && ArgSortCase == SortCase::Func) ||
395
0
            (Kind == IndexKind::CoreType && ArgSortCase == SortCase::Type)) {
396
0
          return true;
397
0
        }
398
399
0
        spdlog::error("[Sort Case] Type mismatch: Expected '{}' but got '{}'"sv,
400
0
                      WasmEdge::Validator::toString(Kind),
401
0
                      WasmEdge::Validator::toString(ArgSortCase));
402
0
        return false;
403
0
      }
404
0
    }
405
406
0
    spdlog::error(
407
0
        "Unhandled type comparison: ImportType and ArgSort do not match any known case."sv);
408
0
    return false;
409
0
  }
410
411
0
  bool isValidArgumentIndex(const Sort &ArgSort, const uint32_t Idx) {
412
0
    if (std::holds_alternative<SortCase>(ArgSort)) {
413
0
      auto ArgSortCase = std::get<SortCase>(ArgSort);
414
0
      if (Ctx.getComponentIndexSize(ArgSortCase) > Idx) {
415
0
        return true;
416
0
      }
417
0
    } else {
418
0
      auto ArgSortCase = std::get<CoreSort>(ArgSort);
419
0
      if (Ctx.getCoreIndexSize(ArgSortCase) > Idx) {
420
0
        return true;
421
0
      }
422
0
    }
423
0
    return false;
424
0
  }
425
};
426
427
struct AliasTargetVisitor {
428
0
  AliasTargetVisitor(const Sort &S, Context &Ctx) : S{S}, Ctx(Ctx) {}
429
430
0
  Expect<void> operator()(const AliasTargetExport &ATE) {
431
0
    auto Idx = ATE.getInstanceIdx();
432
0
    auto Name = ATE.getName();
433
434
0
    if (std::holds_alternative<CoreSort>(S)) {
435
0
      if (Idx >= Ctx.getCoreInstanceExportsSize()) {
436
0
        spdlog::error(ErrCode::Value::InvalidIndex);
437
0
        spdlog::error(
438
0
            "AliasTargetExport: Export index {} exceeds available core instance index {}"sv,
439
0
            Idx, Ctx.getCoreInstanceExportsSize() - 1);
440
0
        return Unexpect(ErrCode::Value::InvalidIndex);
441
0
      }
442
0
      const auto &CoreExports = Ctx.getCoreInstanceExports(Idx);
443
0
      auto CoreS = std::get<CoreSort>(S);
444
445
0
      auto It = CoreExports.find(Name);
446
0
      if (It == CoreExports.end()) {
447
0
        spdlog::error(ErrCode::Value::ExportNotFound);
448
0
        spdlog::error(
449
0
            "AliasTargetExport: No matching export '{}' found in core instance index {}"sv,
450
0
            Name, Idx);
451
0
        return Unexpect(ErrCode::Value::ExportNotFound);
452
0
      }
453
454
0
      const auto &ExternTy = It->second;
455
0
      std::optional<CoreSort> MappedSort = mapExternalTypeToCoreSort(ExternTy);
456
457
0
      if (MappedSort && *MappedSort == CoreS) {
458
0
        return {};
459
0
      } else {
460
0
        spdlog::error(ErrCode::Value::InvalidTypeReference);
461
0
        spdlog::error(
462
0
            "AliasTargetExport: Type mapping mismatch for export '{}': expected {}, got {}"sv,
463
0
            Name, toString(CoreS),
464
0
            MappedSort ? toString(*MappedSort) : "none"sv);
465
0
        return Unexpect(ErrCode::Value::InvalidTypeReference);
466
0
      }
467
0
    } else if (std::holds_alternative<SortCase>(S)) {
468
0
      if (Idx >= Ctx.getComponentInstanceExportsSize()) {
469
0
        spdlog::error(ErrCode::Value::InvalidIndex);
470
0
        spdlog::error(
471
0
            "AliasTargetExport: Export index {} exceeds available component instance index {}"sv,
472
0
            Idx, Ctx.getComponentInstanceExportsSize() - 1);
473
0
        return Unexpect(ErrCode::Value::InvalidIndex);
474
0
      }
475
0
      const auto &ComponentExports = Ctx.getComponentInstanceExports(Idx);
476
0
      auto SortC = std::get<SortCase>(S);
477
478
0
      auto It = ComponentExports.find(Name);
479
0
      if (It == ComponentExports.end()) {
480
0
        spdlog::error(ErrCode::Value::ExportNotFound);
481
0
        spdlog::error(
482
0
            "AliasTargetExport: No matching export '{}' found in component instance index {}"sv,
483
0
            Name, Idx);
484
0
        return Unexpect(ErrCode::Value::ExportNotFound);
485
0
      }
486
487
0
      const auto &ExternDesc = It->second;
488
0
      std::optional<SortCase> MappedSort = mapExternDescToSortCase(ExternDesc);
489
490
0
      if (MappedSort && *MappedSort == SortC) {
491
0
        return {};
492
0
      } else {
493
0
        spdlog::error(ErrCode::Value::InvalidTypeReference);
494
0
        spdlog::error(
495
0
            "AliasTargetExport: Type mapping mismatch for export '{}': expected {}, got {}"sv,
496
0
            Name, toString(SortC),
497
0
            MappedSort ? toString(*MappedSort) : "none"sv);
498
0
        return Unexpect(ErrCode::Value::InvalidTypeReference);
499
0
      }
500
0
    } else {
501
0
      assumingUnreachable();
502
0
    }
503
0
    return {};
504
0
  }
505
506
0
  Expect<void> operator()(const AliasTargetOuter &ATO) {
507
0
    const auto &ComponentIdx = ATO.getComponent();
508
0
    const auto &Idx = ATO.getIndex();
509
510
0
    uint32_t EnclosingComponentCount = 0;
511
0
    const auto *CurrentContext = &Ctx.getCurrentContext();
512
0
    while (CurrentContext->Parent.has_value()) {
513
0
      EnclosingComponentCount++;
514
0
      CurrentContext = CurrentContext->Parent.value();
515
0
    }
516
517
0
    if (ComponentIdx > EnclosingComponentCount) {
518
0
      spdlog::error(ErrCode::Value::InvalidIndex);
519
0
      spdlog::error(
520
0
          "AliasTargetOuter: ComponentIdx {} is exceeding the enclosing component count {}"sv,
521
0
          ComponentIdx, EnclosingComponentCount);
522
0
      return Unexpect(ErrCode::Value::InvalidIndex);
523
0
    }
524
525
0
    const Context::ComponentContext *TargetContext = &Ctx.getCurrentContext();
526
0
    uint32_t Steps = ComponentIdx;
527
0
    while (Steps > 0 && TargetContext != nullptr) {
528
0
      if (TargetContext->Parent.has_value()) {
529
0
        TargetContext = TargetContext->Parent.value();
530
0
        --Steps;
531
0
      } else {
532
0
        assumingUnreachable();
533
0
      }
534
0
    }
535
536
0
    if (std::holds_alternative<SortCase>(S)) {
537
0
      auto &Sort = std::get<SortCase>(S);
538
0
      auto It = TargetContext->getComponentIndexSize(Sort);
539
0
      spdlog::debug("{}", toString(Sort));
540
0
      if (Idx >= It) {
541
0
        spdlog::error(ErrCode::Value::InvalidIndex);
542
0
        spdlog::error(
543
0
            "AliasTargetOuter: Index {} invalid for SortCase in component context"sv,
544
0
            ATO.getIndex());
545
0
        return Unexpect(ErrCode::Value::InvalidIndex);
546
0
      }
547
0
    } else if (std::holds_alternative<CoreSort>(S)) {
548
0
      auto &Sort = std::get<CoreSort>(S);
549
0
      auto It = TargetContext->getCoreIndexSize(Sort);
550
0
      if (Idx >= It) {
551
0
        spdlog::error(ErrCode::Value::InvalidIndex);
552
0
        spdlog::error(
553
0
            "AliasTargetOuter: Index {} invalid for CoreSort in component context"sv,
554
0
            Idx);
555
0
        return Unexpect(ErrCode::Value::InvalidIndex);
556
0
      }
557
0
    } else {
558
0
      assumingUnreachable();
559
0
    }
560
561
0
    if (std::holds_alternative<SortCase>(S)) {
562
0
      auto Sort = std::get<SortCase>(S);
563
564
0
      if (Sort != SortCase::Type && Sort != SortCase::Component) {
565
0
        spdlog::error(ErrCode::Value::InvalidTypeReference);
566
0
        spdlog::error(
567
0
            "AliasTargetOuter: Invalid sort for outer alias: {}. Only type, module, or component are allowed."sv,
568
0
            toString(Sort));
569
0
        return Unexpect(ErrCode::Value::InvalidTypeReference);
570
0
      }
571
572
0
      if (Sort == SortCase::Type) {
573
0
        if (TargetContext->ComponentResourceTypes.find(Idx) !=
574
0
            TargetContext->ComponentResourceTypes.end()) {
575
0
          spdlog::error(ErrCode::Value::InvalidTypeReference);
576
0
          spdlog::error(
577
0
              "AliasTargetOuter: Cannot outer-alias a resource type at index {}. Resource types are generative."sv,
578
0
              Idx);
579
0
          return Unexpect(ErrCode::Value::InvalidTypeReference);
580
0
        }
581
0
      }
582
583
0
    } else if (std::holds_alternative<CoreSort>(S)) {
584
0
      auto Sort = std::get<CoreSort>(S);
585
586
0
      if (Sort != CoreSort::Module && Sort != CoreSort::Type) {
587
0
        spdlog::error(ErrCode::Value::InvalidTypeReference);
588
0
        spdlog::error(
589
0
            "AliasTargetOuter: Invalid sort for outer alias: {}. Only type, module, or component are allowed."sv,
590
0
            toString(Sort));
591
0
        return Unexpect(ErrCode::Value::InvalidTypeReference);
592
0
      }
593
0
    }
594
595
0
    return {};
596
0
  }
597
598
private:
599
  const Sort &S;
600
  Context &Ctx;
601
602
  static inline std::optional<CoreSort>
603
0
  mapExternalTypeToCoreSort(WasmEdge::ExternalType ExtType) {
604
0
    using WasmEdge::ExternalType;
605
0
    switch (ExtType) {
606
0
    case ExternalType::Function:
607
0
      return CoreSort::Func;
608
0
    case ExternalType::Table:
609
0
      return CoreSort::Table;
610
0
    case ExternalType::Memory:
611
0
      return CoreSort::Memory;
612
0
    case ExternalType::Global:
613
0
      return CoreSort::Global;
614
0
    default:
615
0
      return std::nullopt;
616
0
    }
617
0
  }
618
619
  static inline std::optional<SortCase>
620
0
  mapExternDescToSortCase(const ExternDesc &Desc) {
621
0
    if (std::holds_alternative<DescTypeIndex>(Desc)) {
622
0
      const auto &DTI = std::get<DescTypeIndex>(Desc);
623
0
      switch (DTI.getKind()) {
624
0
      case IndexKind::FuncType:
625
0
        return SortCase::Func;
626
0
      case IndexKind::ComponentType:
627
0
        return SortCase::Component;
628
0
      case IndexKind::InstanceType:
629
0
        return SortCase::Instance;
630
0
      default:
631
0
        return std::nullopt;
632
0
      }
633
0
    } else if (std::holds_alternative<TypeBound>(Desc)) {
634
0
      return SortCase::Type;
635
0
    } else if (std::holds_alternative<ValueType>(Desc)) {
636
0
      return SortCase::Type;
637
0
    }
638
0
    return std::nullopt;
639
0
  }
640
};
641
642
struct CoreModuleDeclVisitor {
643
  // TODO: Validation of core:moduledecl rejects core:moduletype
644
  // definitions and outer aliases of core:moduletype definitions inside
645
  // type declarators. Thus, as an invariant, when validating a
646
  // core:moduletype, the core type index space will not contain any
647
  // core module types.
648
0
  Expect<void> operator()(const AST::ImportDesc &) { return {}; }
649
0
  Expect<void> operator()(const std::shared_ptr<CoreType> &) { return {}; }
650
0
  Expect<void> operator()(const Alias &) { return {}; }
651
0
  Expect<void> operator()(const CoreExportDecl &) { return {}; }
652
};
653
struct CoreDefTypeVisitor {
654
0
  CoreDefTypeVisitor(Context &Ctx) : Ctx(Ctx) {}
655
656
0
  Expect<void> operator()(const AST::FunctionType &) {
657
0
    Ctx.incCoreIndexSize(CoreSort::Type);
658
0
    return {};
659
0
  }
660
0
  Expect<void> operator()(const CoreModuleType &Mod) {
661
0
    for (const CoreModuleDecl &D : Mod.getContent()) {
662
0
      EXPECTED_TRY(std::visit(CoreModuleDeclVisitor{}, D));
663
0
    }
664
0
    return {};
665
0
  }
666
667
private:
668
  Context &Ctx;
669
};
670
671
struct DefTypeVisitor {
672
0
  DefTypeVisitor(Context &Ctx) : Ctx(Ctx) {}
673
674
0
  Expect<void> operator()(const DefValType &) {
675
    // TODO: Validation of valtype requires the typeidx to refer to a
676
    // defvaltype.
677
678
    // TODO: Validation of own and borrow requires the typeidx to refer to a
679
    // resource type.
680
0
    Ctx.incComponentIndexSize(SortCase::Type);
681
0
    return {};
682
0
  }
683
0
  Expect<void> operator()(const FuncType &) {
684
    // TODO: Validation of functype rejects any transitive use of borrow in
685
    // a result type. Similarly, validation of components and component
686
    // types rejects any transitive use of borrow in an exported value type.
687
0
    Ctx.incComponentIndexSize(SortCase::Type);
688
0
    return {};
689
0
  }
690
0
  Expect<void> operator()(const ComponentType &CT) {
691
0
    for (auto &Decl : CT.getContent()) {
692
0
      if (std::holds_alternative<ImportDecl>(Decl)) {
693
0
        auto &I = std::get<ImportDecl>(Decl);
694
0
        check(I.getExternDesc());
695
0
      } else if (std::holds_alternative<InstanceDecl>(Decl)) {
696
0
        check(std::get<InstanceDecl>(Decl));
697
0
      }
698
0
      Ctx.incComponentIndexSize(SortCase::Type);
699
0
    }
700
    // TODO: Validation rejects resourcetype type definitions inside
701
    // componenttype and instancettype. Thus, handle types inside a
702
    // componenttype can only refer to resource types that are imported or
703
    // exported.
704
705
    // TODO: As described in the explainer, each component and instance type
706
    // is validated with an initially-empty type index space. Outer aliases
707
    // can be used to pull in type definitions from containing components.
708
709
0
    return {};
710
0
  }
711
0
  Expect<void> operator()(const InstanceType &IT) {
712
0
    Ctx.incComponentIndexSize(SortCase::Type);
713
0
    Ctx.addComponentInstanceType(
714
0
        static_cast<uint32_t>(Ctx.getComponentIndexSize(SortCase::Type) - 1),
715
0
        IT);
716
0
    return {};
717
0
  }
718
0
  Expect<void> operator()(const ResourceType &RT) {
719
0
    Ctx.incComponentIndexSize(SortCase::Type);
720
0
    Ctx.addComponentResourceType(
721
0
        static_cast<uint32_t>(Ctx.getComponentIndexSize(SortCase::Type) - 1),
722
0
        RT);
723
0
    return {};
724
0
  }
725
726
0
  void check(const InstanceDecl &) {
727
    // TODO: Validation of instancedecl (currently) only allows the type and
728
    // instance sorts in alias declarators.
729
0
  }
730
731
0
  void check(const ExternDesc &) {
732
    // TODO: Validation of externdesc requires the various typeidx type
733
    // constructors to match the preceding sort.
734
0
  }
735
736
private:
737
  Context &Ctx;
738
};
739
struct CanonVisitor {
740
0
  CanonVisitor(Context &Ctx) : Ctx(Ctx) {}
741
742
0
  Expect<void> operator()(const Lift &) {
743
    // TODO: validation specifies
744
    // = $callee must have type flatten_functype($opts, $ft, 'lift')
745
    // = $f is given type $ft
746
    // = a memory is present if required by lifting and is a subtype of
747
    //       (memory 1)
748
    // = a realloc is present if required by lifting and has type
749
    //       (func (param i32 i32 i32 i32) (result i32))
750
    // = if a post-return is present, it has type
751
    //       (func (param flatten_functype({}, $ft, 'lift').results))
752
0
    Ctx.incComponentIndexSize(SortCase::Func);
753
0
    return {};
754
0
  }
755
0
  Expect<void> operator()(const Lower &) {
756
    // TODO: where $callee has type $ft, validation specifies
757
    // = $f is given type flatten_functype($opts, $ft, 'lower')
758
    // = a memory is present if required by lifting and is a subtype of
759
    //     (memory 1)
760
    // = a realloc is present if required by lifting and has type
761
    //     (func (param i32 i32 i32 i32) (result i32))
762
    // = there is no post-return in $opts
763
0
    Ctx.incCoreIndexSize(CoreSort::Func);
764
0
    return {};
765
0
  }
766
0
  Expect<void> operator()(const ResourceNew &) {
767
    // TODO: validation specifies
768
    // = $rt must refer to locally-defined (not imported) resource type
769
    // = $f is given type (func (param $rt.rep) (result i32)), where $rt.rep is
770
    // currently fixed to be i32.
771
0
    Ctx.incCoreIndexSize(CoreSort::Func);
772
0
    return {};
773
0
  }
774
0
  Expect<void> operator()(const ResourceDrop &) {
775
    // TODO: validation specifies
776
    // = $rt must refer to resource type
777
    // = $f is given type (func (param i32))
778
0
    Ctx.incCoreIndexSize(CoreSort::Func);
779
0
    return {};
780
0
  }
781
0
  Expect<void> operator()(const ResourceRep &) {
782
    // TODO: validation specifies
783
    // = $rt must refer to a locally-defined (not imported) resource type
784
    // = $f is given type (func (param i32) (result $rt.rep)), where $rt.rep is
785
    // currently fixed to be i32.
786
0
    Ctx.incCoreIndexSize(CoreSort::Func);
787
0
    return {};
788
0
  }
789
  // TODO: The following are not yet exists in WasmEdge, so just list entries
790
  // 1. canon task.backpressure
791
  // 2. canon task.start
792
  // 3. canon task.return
793
  // 4. canon task.wait
794
  // 5. canon task.poll
795
  // 6. canon task.yield
796
  // 7. canon thread.spawn
797
  // 8. canon thread.hw_concurrency
798
private:
799
  Context &Ctx;
800
};
801
802
struct SectionVisitor {
803
0
  SectionVisitor(Validator &V, Context &Ctx) : V(V), Ctx(Ctx) {}
804
805
0
  Expect<void> operator()(const AST::CustomSection &) {
806
0
    spdlog::debug("Custom Section"sv);
807
0
    return {};
808
0
  }
809
0
  Expect<void> operator()(const CoreModuleSection &Sec) {
810
0
    spdlog::debug("CoreModule Section"sv);
811
0
    auto &Mod = Sec.getContent();
812
0
    V.validate(Mod);
813
0
    Ctx.addCoreModule(Mod);
814
0
    Ctx.incCoreIndexSize(CoreSort::Module);
815
0
    return {};
816
0
  }
817
0
  Expect<void> operator()(const ComponentSection &Sec) {
818
0
    spdlog::debug("Component Section"sv);
819
0
    auto &C = Sec.getContent();
820
0
    V.validate(C);
821
0
    Ctx.incComponentIndexSize(SortCase::Component);
822
0
    return {};
823
0
  }
824
0
  Expect<void> operator()(const CoreInstanceSection &Sec) {
825
0
    spdlog::debug("CoreInstance Section"sv);
826
0
    for (const CoreInstanceExpr &E : Sec.getContent()) {
827
0
      CoreInstanceExprVisitor Visitor{Ctx};
828
0
      EXPECTED_TRY(std::visit(Visitor, E));
829
0
    }
830
    // NOTE: refers below InstanceSection, and copy the similar structure
831
832
    // TODO: Validation of core:instantiatearg initially only allows the
833
    // instance sort, but would be extended to accept other sorts as core wasm
834
    // is extended.
835
0
    return {};
836
0
  }
837
0
  Expect<void> operator()(const InstanceSection &Sec) {
838
0
    spdlog::debug("Instance Section"sv);
839
0
    for (const InstanceExpr &E : Sec.getContent()) {
840
0
      InstanceExprVisitor Visitor{Ctx};
841
0
      EXPECTED_TRY(std::visit(Visitor, E));
842
0
    }
843
0
    return {};
844
0
  }
845
0
  Expect<void> operator()(const AliasSection &Sec) {
846
0
    spdlog::debug("Alias Section"sv);
847
0
    for (const Alias &A : Sec.getContent()) {
848
0
      EXPECTED_TRY(
849
0
          std::visit(AliasTargetVisitor{A.getSort(), Ctx}, A.getTarget()));
850
0
      auto Sort = A.getSort();
851
0
      if (std::holds_alternative<SortCase>(Sort)) {
852
0
        Ctx.incComponentIndexSize(std::get<SortCase>(Sort));
853
0
      } else if (std::holds_alternative<CoreSort>(Sort)) {
854
0
        Ctx.incCoreIndexSize(std::get<CoreSort>(Sort));
855
0
      }
856
0
    }
857
0
    return {};
858
0
  }
859
0
  Expect<void> operator()(const CoreTypeSection &Sec) {
860
0
    spdlog::debug("CoreType Section"sv);
861
    // TODO: As described in the explainer, each module type is validated with
862
    // an initially-empty type index space.
863
0
    for (const CoreDefType &T : Sec.getContent()) {
864
0
      CoreDefTypeVisitor Visitor{Ctx};
865
0
      EXPECTED_TRY(std::visit(Visitor, T));
866
0
    }
867
0
    return {};
868
0
  }
869
0
  Expect<void> operator()(const TypeSection &Sec) {
870
0
    spdlog::debug("Type Section"sv);
871
0
    for (const DefType &T : Sec.getContent()) {
872
0
      DefTypeVisitor Visitor{Ctx};
873
0
      EXPECTED_TRY(std::visit(Visitor, T));
874
0
    }
875
    // TODO: Validation of resourcetype requires the destructor (if present) to
876
    // have type [i32] -> [].
877
878
0
    return {};
879
0
  }
880
0
  Expect<void> operator()(const CanonSection &Sec) {
881
0
    spdlog::debug("Canon Section"sv);
882
    // TODO: Validation prevents duplicate or conflicting canonopt.
883
0
    for (const Canon &C : Sec.getContent()) {
884
0
      CanonVisitor Visitor{Ctx};
885
0
      EXPECTED_TRY(std::visit(Visitor, C));
886
0
    }
887
888
0
    return {};
889
0
  }
890
0
  Expect<void> operator()(const StartSection &) {
891
0
    spdlog::debug("Start Section"sv);
892
    // API:
893
    // const Start &S = Sec.getContent();
894
    // S.getFunctionIndex();
895
    // S.getArguments();
896
    // S.getResult();
897
898
    // TODO: Validation requires f have functype with param arity and types
899
    // matching arg* and result arity r.
900
901
    // TODO: Validation appends the result types of f to the value index space
902
    // (making them available for reference by subsequent definitions).
903
904
    // TODO: In addition to the type-compatibility checks mentioned above, the
905
    // validation rules for value definitions additionally require that each
906
    // value is consumed exactly once. Thus, during validation, each value has
907
    // an associated "consumed" boolean flag. When a value is first added to
908
    // the value index space (via import, instance, alias or start), the flag
909
    // is clear. When a value is used (via export, instantiate or start), the
910
    // flag is set. After validating the last definition of a component,
911
    // validation requires all values' flags are set.
912
913
0
    return {};
914
0
  }
915
0
  Expect<void> operator()(const ImportSection &Sec) {
916
0
    spdlog::debug("Import Section"sv);
917
    // NOTE: This section share the validation rules with export section, one
918
    // must share the implementation as much as possible.
919
0
    for (const Import &I : Sec.getContent()) {
920
      // TODO: Validation requires that annotated plainnames only occur on func
921
      // imports or exports and that the first label of a [constructor],
922
      // [method] or [static] matches the plainname of a preceding resource
923
      // import or export, respectively, in the same scope (component, component
924
      // type or instance type).
925
926
      // TODO: Validation of [constructor] names requires that the func returns
927
      // a (result (own $R)), where $R is the resource labeled r.
928
929
      // TODO: Validation of [method] names requires the first parameter of the
930
      // function to be (param "self" (borrow $R)), where $R is the resource
931
      // labeled r.
932
933
      // TODO: Validation of [method] and [static] names ensures that all field
934
      // names are disjoint.
935
0
      I.getName();
936
937
0
      ExternDescVisitor Visitor{Ctx};
938
0
      EXPECTED_TRY(std::visit(Visitor, I.getDesc()));
939
0
    }
940
    // TODO: Validation requires that all resource types transitively used in
941
    // the type of an export are introduced by a preceding importdecl or
942
    // exportdecl.
943
944
0
    return {};
945
0
  }
946
0
  Expect<void> operator()(const ExportSection &Sec) {
947
0
    spdlog::debug("Export Section"sv);
948
0
    for (const Export &E : Sec.getContent()) {
949
0
      auto SI = E.getSortIndex();
950
0
      auto Sort = SI.getSort();
951
0
      SI.getSortIdx();
952
0
      if (E.getDesc().has_value()) {
953
        // TODO: Validation requires any exported sortidx to have a valid
954
        // externdesc (which disallows core sorts other than core module). When
955
        // the optional externdesc immediate is present, validation requires it
956
        // to be a supertype of the inferred externdesc of the sortidx.
957
0
        ExternDescVisitor Visitor{Ctx};
958
0
        EXPECTED_TRY(std::visit(Visitor, *E.getDesc()));
959
0
      } else if (std::holds_alternative<SortCase>(Sort)) {
960
0
        auto SC = std::get<SortCase>(Sort);
961
0
        Ctx.incComponentIndexSize(SC);
962
0
      }
963
0
    }
964
965
0
    return {};
966
0
  }
967
968
private:
969
  Validator &V;
970
  Context &Ctx;
971
};
972
973
} // namespace Validator
974
} // namespace WasmEdge