Repository: WasmEdge/WasmEdge
Pull request #4062: [Component Validation] Validate instantiate imports and arguments
Author: login: sridamul
Labels: name: v-0.15.0
name: WASM-ComponentModel
description: https://github.com/WebAssembly/component-model
Created: 2025-03-18T16:33:33Z | Merged: 2025-03-24T01:31:17Z

Validates each <importname> in `c` must match a name in `a` with an argument, compared as strings. Types must match for the validation to pass.

Maintaining the Context class, will be extended in future to store the index spaces for further validation.

ref: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md


Diff:
diff --git a/include/common/enum.inc b/include/common/enum.inc
index 49f9f673a54c..c57dfe55fd2b 100644
--- a/include/common/enum.inc
+++ b/include/common/enum.inc
@@ -1074,6 +1074,14 @@ E(UnknownCanonicalOption, 0x050A, "unknown canonical option")
 E(MalformedName, 0x050B, "malformed name")
 // @}
 
+// Component model validation phase
+// @{
+// Missing Argument
+E(MissingArgument, 0x050C, "missing argument")
+// Argument Type Mismatch with Import Type
+E(ArgTypeMismatch, 0x050D, "type mismatch")
+// @}
+
 // Component model instantiation phase
 // @{
 E(CoreInvalidExport, 0x0600, "invalid export in core module")
diff --git a/include/validator/validator_component.h b/include/validator/validator_component.h
index 6dd4efdc53a7..8e0fd5ce011c 100644
--- a/include/validator/validator_component.h
+++ b/include/validator/validator_component.h
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-FileCopyrightText: 2019-2024 Second State INC
+#include "common/errinfo.h"
 #include "validator/validator.h"
 
 namespace WasmEdge {
@@ -7,6 +8,59 @@ namespace Validator {
 
 using namespace AST::Component;
 
+// Helper func for better logging
+inline std::string toString(SortCase SC) {
+  switch (SC) {
+  case SortCase::Func:
+    return "Func";
+  case SortCase::Value:
+    return "Value";
+  case SortCase::Type:
+    return "Type";
+  case SortCase::Component:
+    return "Component";
+  case SortCase::Instance:
+    return "Instance";
+  default:
+    return "Unknown SortCase";
+  }
+}
+
+inline std::string toString(CoreSort CS) {
+  switch (CS) {
+  case CoreSort::Func:
+    return "Func";
+  case CoreSort::Table:
+    return "Table";
+  case CoreSort::Memory:
+    return "Memory";
+  case CoreSort::Global:
+    return "Global";
+  case CoreSort::Type:
+    return "Type";
+  case CoreSort::Module:
+    return "Module";
+  case CoreSort::Instance:
+    return "Instance";
+  default:
+    return "Unknown CoreSort";
+  }
+}
+
+class Context {
+public:
+  void addComponent(const Component &C) noexcept { CompList.emplace_back(C); }
+
+  const Component &getComponent(uint32_t Index) const noexcept {
+    return CompList[Index];
+  }
+
+  size_t getComponentCount() const noexcept { return CompList.size(); }
+
+private:
+  std::vector<Component> CompList;
+};
+
 struct ExternDescVisitor {
   Expect<void> operator()(const DescTypeIndex &) { return {}; }
   Expect<void> operator()(const TypeBound &) {
@@ -17,10 +71,33 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
+    auto Args = Inst.getArgs();
+    auto ImportMap = getImports(Inst.getComponentIdx());
+
+    for (auto it = ImportMap.begin(); it != ImportMap.end(); ++it) {
+      const auto &ImportName = it->first;
+      const auto &ImportDesc = it->second;
+      auto argIt = std::find_if(Args.begin(), Args.end(), [&](const auto &Arg) {
+        return Arg.getName() == ImportName;
+      });
+
+      if (argIt == Args.end()) {
+        spdlog::error(ErrCode::Value::MissingArgument);
+        spdlog::error("Component[{}]: Missing argument for import '{}'",
+                      Inst.getComponentIdx(), ImportName);
+        return Unexpect(ErrCode::Value::MissingArgument);
+      }
+
+      if (!matchImportAndArgTypes(ImportDesc, argIt->getIndex().getSort())) {
+        spdlog::error(ErrCode::Value::ArgTypeMismatch);
+        spdlog::error("Component[{}]: Argument '{}' type mismatch",
+                      Inst.getComponentIdx(), ImportName);
+        return Unexpect(ErrCode::Value::ArgTypeMismatch);
+      }
+    }
 
     // TODO: The indices in sortidx are validated according to their sort's
     // index spaces, which are built incrementally as each definition is
@@ -34,6 +111,107 @@ struct InstanceExprVisitor {
     // and all exports are now specialized to the actual type.
     return {};
   }
+
+private:
+  Context &Ctx;
+
+  std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) {
+    std::unordered_map<std::string, ExternDesc> ImportMap;
+
+    if (Index >= Ctx.getComponentCount()) {
+      spdlog::error("Unreachable State: Index {} exceeds Component Count {}",
+                    Index, Ctx.getComponentCount());
+      spdlog::error(WasmEdge::ErrInfo::InfoBoundary(
+          Index, 0, static_cast<uint32_t>(Ctx.getComponentCount())));
+
+      return ImportMap;
+    }
+
+    auto &Comp = Ctx.getComponent(Index);
+
+    for (const auto &Sec : Comp.getSections()) {
+      if (std::holds_alternative<ImportSection>(Sec)) {
+        const auto &ImportSec = std::get<ImportSection>(Sec);
+
+        for (const auto &Import : ImportSec.getContent()) {
+          ImportMap[std::string(Import.getName())] = Import.getDesc();
+        }
+      }
+    }
+
+    return ImportMap;
+  }
+
+  // https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md
+  bool matchImportAndArgTypes(const ExternDesc &ImportType,
+                              const Sort &ArgSort) {
+    if (std::holds_alternative<CoreSort>(ArgSort)) {
+      CoreSort ArgCoreSort = std::get<CoreSort>(ArgSort);
+
+      if (std::holds_alternative<DescTypeIndex>(ImportType) &&
+          ArgCoreSort == CoreSort::Type) {
+        return true;
+      }
+
+      if (std::holds_alternative<ValueType>(ImportType)) {
+        if (ArgCoreSort == CoreSort::Func || ArgCoreSort == CoreSort::Table ||
+            ArgCoreSort == CoreSort::Memory ||
+            ArgCoreSort == CoreSort::Global) {
+          return true;
+        }
+        spdlog::error("Type mismatch: Expected 'Func', 'Table', 'Memory', or "
+                      "'Global' but got '{}'",
+                      WasmEdge::Validator::toString(ArgCoreSort));
+        return false;
+      }
+
+      if (std::holds_alternative<TypeBound>(ImportType)) {
+        if (ArgCoreSort == CoreSort::Module ||
+            ArgCoreSort == CoreSort::Instance) {
+          return true;
+        }
+        spdlog::error(
+            "Type mismatch: Expected 'Module' or 'Instance' but got '{}'",
+            WasmEdge::Validator::toString(ArgCoreSort));
+        return false;
+      }
+    }
+
+    if (std::holds_alternative<SortCase>(ArgSort)) {
+      SortCase ArgSortCase = std::get<SortCase>(ArgSort);
+
+      if (std::holds_alternative<TypeBound>(ImportType)) {
+        if (ArgSortCase == SortCase::Instance) {
+          return true;
+        }
+        spdlog::error("Type mismatch: Expected 'Instance' but got '{}'",
+                      WasmEdge::Validator::toString(ArgSortCase));
+        return false;
+      }
+
+      if (std::holds_alternative<ValueType>(ImportType)) {
+        if (ArgSortCase == SortCase::Value) {
+          return true;
+        }
+        spdlog::error("Type mismatch: Expected 'Value' but got '{}'",
+                      WasmEdge::Validator::toString(ArgSortCase));
+        return false;
+      }
+
+      if (std::holds_alternative<DescTypeIndex>(ImportType)) {
+        if (ArgSortCase == SortCase::Type) {
+          return true;
+        }
+        spdlog::error("Type mismatch: Expected 'Type' but got '{}'",
+                      WasmEdge::Validator::toString(ArgSortCase));
+        return false;
+      }
+    }
+
+    spdlog::error("Unhandled type comparison: ImportType and ArgSort do not "
+                  "match any known case.");
+    return false;
+  }
 };
 
 struct AliasTargetVisitor {
@@ -184,7 +362,7 @@ struct CanonVisitor {
 };
 
 struct SectionVisitor {
-  SectionVisitor(Validator &V) : V(V) {}
+  SectionVisitor(Validator &V, Context &Ctx) : V(V), Ctx(Ctx) {}
 
   Expect<void> operator()(const AST::CustomSection &) { return {}; }
   Expect<void> operator()(const AST::CoreModuleSection &Sec) {
@@ -195,6 +373,7 @@ struct SectionVisitor {
   Expect<void> operator()(const ComponentSection &Sec) {
     auto &C = Sec.getContent();
     V.validate(C);
+    Ctx.addComponent(C);
     return {};
   }
   Expect<void> operator()(const CoreInstanceSection &) {
@@ -207,7 +386,8 @@ struct SectionVisitor {
   }
   Expect<void> operator()(const InstanceSection &Sec) {
     for (const InstanceExpr &E : Sec.getContent()) {
-      EXPECTED_TRY(std::visit(InstanceExprVisitor{}, E));
+      InstanceExprVisitor Visitor(Ctx);
+      EXPECTED_TRY(std::visit(Visitor, E));
     }
     return {};
   }
@@ -314,6 +494,7 @@ struct SectionVisitor {
 
 private:
   Validator &V;
+  Context &Ctx;
 };
 
 } // namespace Validator
diff --git a/lib/validator/validator_component.cpp b/lib/validator/validator_component.cpp
index bed81bd5716f..f69ee2b486b0 100644
--- a/lib/validator/validator_component.cpp
+++ b/lib/validator/validator_component.cpp
@@ -14,8 +14,10 @@ using namespace AST::Component;
 Expect<void> Validator::validate(const AST::Component::Component &Comp) {
   spdlog::warn("component validation is not done yet."sv);
 
+  Context Ctx;
+
   for (auto &Sec : Comp.getSections()) {
-    EXPECTED_TRY(std::visit(SectionVisitor{*this}, Sec));
+    EXPECTED_TRY(std::visit(SectionVisitor{*this, Ctx}, Sec));
   }
 
   return {};


Reviews:
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T00:40:35Z
user: login: dannypsnl
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-19T00:52:48Z
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T01:27:21Z
user: login: dannypsnl
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-19T04:33:55Z
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T04:38:51Z
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T04:40:03Z
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T04:43:42Z
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T04:50:55Z
user: login: sridamul
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T18:53:24Z
user: login: sridamul
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T05:30:39Z
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T08:41:37Z
user: login: dannypsnl
state: DISMISSED
author_association: MEMBER
submitted_at: 2025-03-21T08:43:46Z
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T09:34:14Z
user: login: dannypsnl
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T09:35:27Z
user: login: dannypsnl
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-24T01:27:28Z

Review comments:
diff_hunk: @@ -7,6 +7,22 @@ namespace Validator {
 
 using namespace AST::Component;
 
+class Context {
+public:
+  Context() = default;
path: include/validator/validator_component.h
user: login: dannypsnl
body: default constructor can be omitted.
created_at: 2025-03-19T00:40:35Z
author_association: MEMBER
diff_hunk: @@ -34,6 +66,48 @@ struct InstanceExprVisitor {
     // and all exports are now specialized to the actual type.
     return {};
   }
+
+private:
+  Context &Ctx;
+
+  std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) {
+    std::unordered_map<std::string, ExternDesc> ImportMap;
+
+    if (Index >= Ctx.getComponentCount()) {
+      return ImportMap;
+    }
+
+    auto &Comp = Ctx.getComponent(Index);
+
+    for (const auto &Sec : Comp.getSections()) {
+      if (std::holds_alternative<ImportSection>(Sec)) {
+        const auto &ImportSec = std::get<ImportSection>(Sec);
+
+        for (const auto &Import : ImportSec.getContent()) {
+          ImportMap[std::string(Import.getName())] = Import.getDesc();
+        }
+      }
+    }
+
+    return ImportMap;
+  }
+
+  bool matchImportAndArgTypes(const ExternDesc &ImportType,
+                              const Sort &ArgSort) {
+    SortCase ArgSortCase = std::get<SortCase>(ArgSort);
+
+    if (std::holds_alternative<TypeBound>(ImportType)) {
+      return ArgSortCase == SortCase::Instance;
+    }
+    if (std::holds_alternative<ValueType>(ImportType)) {
+      return ArgSortCase == SortCase::Value;
+    }
+    if (std::holds_alternative<DescTypeIndex>(ImportType)) {
+      return ArgSortCase == SortCase::Type;
+    }
path: include/validator/validator_component.h
user: login: dannypsnl
body: Better use `if ... else if`, otherwise all three branches will run whatever `ImportType` is.
created_at: 2025-03-19T00:44:45Z
author_association: MEMBER
diff_hunk: @@ -34,6 +66,48 @@ struct InstanceExprVisitor {
     // and all exports are now specialized to the actual type.
     return {};
   }
+
+private:
+  Context &Ctx;
+
+  std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) {
+    std::unordered_map<std::string, ExternDesc> ImportMap;
+
+    if (Index >= Ctx.getComponentCount()) {
+      return ImportMap;
+    }
path: include/validator/validator_component.h
user: login: dannypsnl
body: I think better just assuming this is unreachable, and print some errors here.
created_at: 2025-03-19T00:47:25Z
author_association: MEMBER
diff_hunk: @@ -17,10 +33,26 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
+    auto Args = Inst.getArgs();
+    auto Imports = getImports(Inst.getComponentIdx());
path: include/validator/validator_component.h
user: login: dannypsnl
body: Rename `Imports` to `ImportMap` seems more proper.
created_at: 2025-03-19T00:48:33Z
author_association: MEMBER
diff_hunk: @@ -17,10 +33,26 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
+    auto Args = Inst.getArgs();
+    auto Imports = getImports(Inst.getComponentIdx());
+
+    for (const auto &Arg : Args) {
+      const auto &ArgName = Arg.getName();
+      auto it = Imports.find(std::string(ArgName));
+
+      if (it == Imports.end()) {
+        return Unexpect(ErrCode::Value::UnknownArgument);
path: include/validator/validator_component.h
user: login: dannypsnl
body: Print more context errors, e.g.

https://github.com/WasmEdge/WasmEdge/blob/ccef98c7b2422526291d3c77ace0dfc4d992d87a/lib/loader/loader.cpp#L49-L52
created_at: 2025-03-19T00:51:54Z
author_association: MEMBER
diff_hunk: @@ -17,10 +33,26 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
+    auto Args = Inst.getArgs();
+    auto Imports = getImports(Inst.getComponentIdx());
+
+    for (const auto &Arg : Args) {
+      const auto &ArgName = Arg.getName();
+      auto it = Imports.find(std::string(ArgName));
+
+      if (it == Imports.end()) {
+        return Unexpect(ErrCode::Value::UnknownArgument);
+      }
+
+      if (!matchImportAndArgTypes(it->second, Arg.getIndex().getSort())) {
+        return Unexpect(ErrCode::Value::ArgTypeMismatch);
path: include/validator/validator_component.h
user: login: dannypsnl
body: Print more context errors, also
created_at: 2025-03-19T00:52:17Z
author_association: MEMBER
diff_hunk: @@ -1074,6 +1074,14 @@ E(UnknownCanonicalOption, 0x050A, "unknown canonical option")
 E(MalformedName, 0x050B, "malformed name")
 // @}
 
+// Component model validation phase
+// @{
+// Unknown Argument
+E(UnknownArgument, 0x050C, "unknown argument")
+// Argument Type Mistmatch with Import Type
path: include/common/enum.inc
user: login: dannypsnl
body: Mistmatch -> Mismatch
created_at: 2025-03-19T01:27:21Z
author_association: MEMBER
diff_hunk: @@ -34,6 +74,51 @@ struct InstanceExprVisitor {
     // and all exports are now specialized to the actual type.
     return {};
   }
+
+private:
+  Context &Ctx;
+
+  std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) {
+    std::unordered_map<std::string, ExternDesc> ImportMap;
+
+    if (Index >= Ctx.getComponentCount()) {
+      spdlog::error("Unreachable State: Index {} exceeds Component Count {}",
+                    Index, Ctx.getComponentCount());
+      spdlog::error(
+          WasmEdge::ErrInfo::InfoBoundary(Index, 0, Ctx.getComponentCount()));
+
+      return ImportMap;
+    }
+
+    auto &Comp = Ctx.getComponent(Index);
+
+    for (const auto &Sec : Comp.getSections()) {
+      if (std::holds_alternative<ImportSection>(Sec)) {
+        const auto &ImportSec = std::get<ImportSection>(Sec);
+
+        for (const auto &Import : ImportSec.getContent()) {
+          ImportMap[std::string(Import.getName())] = Import.getDesc();
+        }
+      }
+    }
+
+    return ImportMap;
+  }
+
+  bool matchImportAndArgTypes(const ExternDesc &ImportType,
+                              const Sort &ArgSort) {
+    SortCase ArgSortCase = std::get<SortCase>(ArgSort);
+
+    if (std::holds_alternative<TypeBound>(ImportType)) {
+      return ArgSortCase == SortCase::Instance;
+    } else if (std::holds_alternative<ValueType>(ImportType)) {
+      return ArgSortCase == SortCase::Value;
+    } else if (std::holds_alternative<DescTypeIndex>(ImportType)) {
+      return ArgSortCase == SortCase::Type;
+    }
path: include/validator/validator_component.h
user: login: dannypsnl
body: Better add a link to spec in comment, so even future something changes, maintainers can still compare the implementation and spec.
created_at: 2025-03-19T04:33:49Z
author_association: MEMBER
diff_hunk: @@ -17,10 +33,34 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
+    auto Args = Inst.getArgs();
+    auto ImportMap = getImports(Inst.getComponentIdx());
+
+    for (const auto &Arg : Args) {
+      const auto &ArgName = Arg.getName();
+      auto it = ImportMap.find(std::string(ArgName));
+
+      if (it == ImportMap.end()) {
path: include/validator/validator_component.h
user: login: dannypsnl
body: Here you check if `import xxx ...` has no argument `with xxx ...` is correct. However, at the end of this algorithm, you forget to check import map is empty (no missing argument).

I suggest you reverse the relation: each name of an import statement, find a proper argument.
created_at: 2025-03-19T04:38:51Z
author_association: MEMBER
diff_hunk: @@ -34,6 +74,51 @@ struct InstanceExprVisitor {
     // and all exports are now specialized to the actual type.
     return {};
   }
+
+private:
+  Context &Ctx;
+
+  std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) {
+    std::unordered_map<std::string, ExternDesc> ImportMap;
+
+    if (Index >= Ctx.getComponentCount()) {
+      spdlog::error("Unreachable State: Index {} exceeds Component Count {}",
+                    Index, Ctx.getComponentCount());
+      spdlog::error(
+          WasmEdge::ErrInfo::InfoBoundary(Index, 0, Ctx.getComponentCount()));
+
+      return ImportMap;
+    }
+
+    auto &Comp = Ctx.getComponent(Index);
+
+    for (const auto &Sec : Comp.getSections()) {
+      if (std::holds_alternative<ImportSection>(Sec)) {
+        const auto &ImportSec = std::get<ImportSection>(Sec);
+
+        for (const auto &Import : ImportSec.getContent()) {
+          ImportMap[std::string(Import.getName())] = Import.getDesc();
+        }
+      }
+    }
+
+    return ImportMap;
+  }
+
+  bool matchImportAndArgTypes(const ExternDesc &ImportType,
+                              const Sort &ArgSort) {
+    SortCase ArgSortCase = std::get<SortCase>(ArgSort);
path: include/validator/validator_component.h
user: login: dannypsnl
body: `Sort` should have more than just `SortCase` case? From my memory there also has `CoreSort`?
created_at: 2025-03-19T04:40:02Z
author_association: MEMBER
diff_hunk: @@ -194,6 +279,7 @@ struct SectionVisitor {
   }
   Expect<void> operator()(const ComponentSection &Sec) {
     auto &C = Sec.getContent();
+    Ctx.addComponent(C);
     V.validate(C);
path: include/validator/validator_component.h
user: login: dannypsnl
body: Maybe reverse the order more make sense? Check the component first, then use it in further validation.
created_at: 2025-03-19T04:43:42Z
author_association: MEMBER
diff_hunk: @@ -17,10 +33,34 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
+    auto Args = Inst.getArgs();
+    auto ImportMap = getImports(Inst.getComponentIdx());
+
+    for (const auto &Arg : Args) {
+      const auto &ArgName = Arg.getName();
+      auto it = ImportMap.find(std::string(ArgName));
+
+      if (it == ImportMap.end()) {
path: include/validator/validator_component.h
user: login: dannypsnl
body: Here, the big picture of component is more clear: It's a module/class, an instantiation is make/new an instance.

If you familiar with OCaml/Agda, module will be easier; if you familiar with Java/C++, class will be easier to understand.

Each import statement, e.g.
```wasm
(component
  (import "T" (type $T (sub resource)))
  ...)
```
means find a component instance named `"T"` in environment, check it's type is a resource. `$T` is omittable, it binds type of `"T"` to use in the component.
created_at: 2025-03-19T04:50:55Z
author_association: MEMBER
diff_hunk: @@ -34,6 +74,51 @@ struct InstanceExprVisitor {
     // and all exports are now specialized to the actual type.
     return {};
   }
+
+private:
+  Context &Ctx;
+
+  std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) {
+    std::unordered_map<std::string, ExternDesc> ImportMap;
+
+    if (Index >= Ctx.getComponentCount()) {
+      spdlog::error("Unreachable State: Index {} exceeds Component Count {}",
+                    Index, Ctx.getComponentCount());
+      spdlog::error(
+          WasmEdge::ErrInfo::InfoBoundary(Index, 0, Ctx.getComponentCount()));
+
+      return ImportMap;
+    }
+
+    auto &Comp = Ctx.getComponent(Index);
+
+    for (const auto &Sec : Comp.getSections()) {
+      if (std::holds_alternative<ImportSection>(Sec)) {
+        const auto &ImportSec = std::get<ImportSection>(Sec);
+
+        for (const auto &Import : ImportSec.getContent()) {
+          ImportMap[std::string(Import.getName())] = Import.getDesc();
+        }
+      }
+    }
+
+    return ImportMap;
+  }
+
+  bool matchImportAndArgTypes(const ExternDesc &ImportType,
+                              const Sort &ArgSort) {
+    SortCase ArgSortCase = std::get<SortCase>(ArgSort);
path: include/validator/validator_component.h
user: login: sridamul
body: Yeah! I missed that one.
Will update it.
created_at: 2025-03-19T18:53:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,10 +71,31 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
path: include/validator/validator_component.h
user: login: sridamul
body: I am not sure whether it is necessary to check the extra args left.
created_at: 2025-03-21T05:30:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,10 +71,31 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
path: include/validator/validator_component.h
user: login: dannypsnl
body: I think for now let's accept more arguments than needed.
created_at: 2025-03-21T08:41:37Z
author_association: MEMBER
diff_hunk: @@ -17,10 +71,31 @@ struct ExternDescVisitor {
 };
 
 struct InstanceExprVisitor {
-  Expect<void> operator()(const Instantiate &) {
-    // TODO: Validation of instantiate requires each <importname> in c to
-    // match a name in a with argument (compared as strings) and for the
-    // types to match.
+  InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {}
+
+  Expect<void> operator()(const Instantiate &Inst) {
+    auto Args = Inst.getArgs();
+    auto ImportMap = getImports(Inst.getComponentIdx());
+
+    for (const auto &[ImportName, ImportDesc] : ImportMap) {
path: include/validator/validator_component.h
user: login: dannypsnl
body: ![image](https://github.com/user-attachments/assets/6d67e327-76db-4d9f-9c54-6d801088ac8b)

This is C++20 syntax, WasmEdge still using 17 for now, you will need to configure your compiler.
created_at: 2025-03-21T09:34:14Z
author_association: MEMBER
diff_hunk: @@ -34,6 +109,107 @@ struct InstanceExprVisitor {
     // and all exports are now specialized to the actual type.
     return {};
   }
+
+private:
+  Context &Ctx;
+
+  std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) {
+    std::unordered_map<std::string, ExternDesc> ImportMap;
+
+    if (Index >= Ctx.getComponentCount()) {
+      spdlog::error("Unreachable State: Index {} exceeds Component Count {}",
+                    Index, Ctx.getComponentCount());
+      spdlog::error(
+          WasmEdge::ErrInfo::InfoBoundary(Index, 0, Ctx.getComponentCount()));
path: include/validator/validator_component.h
user: login: dannypsnl
body: ![image](https://github.com/user-attachments/assets/5a3a14b3-ca7e-40de-ad66-400bd54f231a)

Need static casting.
created_at: 2025-03-21T09:35:27Z
author_association: MEMBER

PR comments:
user: login: juntao
created_at: 2025-03-18T16:33:37Z
body: Hello, I am a [code review agent](https://github.com/flows-network/github-pr-review/) on [flows.network](https://flows.network/). Here are my reviews of changed source code files in this PR.

------

## [include/common/enum.inc](https://github.com/WasmEdge/WasmEdge/blob/6d1a39db5dc4ab6b9b76034411e8dd1e30f7df32/include%2Fcommon%2Fenum.inc)

#### Potential issues

1. **Duplicate Enum Definition**: The opcode `F64x2__relaxed_madd` and `F64x2__relaxed_nmadd` are incorrectly defined with the same string `"f32x4.relaxed_madd"`. This will lead to confusion and incorrect mapping of opcodes.
   
2. **Missing Enum Definition**: The enum code definition for `E(InvalidConf` is incomplete, ending abruptly without a proper closing parenthesis or error message, which can cause compilation errors or unexpected behavior.

3. **Macro Reuse Without Undefinition**: After the first use of macros like `O`, `OFB`, etc., they are undefined (`#undef`). If this header file is included multiple times, especially with different conditional definitions (like `UseOpCode`), it could lead to redefinition errors because the macros might not be properly reset for subsequent inclusions. Consider resetting these macros or ensuring proper encapsulation within each section.

#### Summary of changes

- - Added new error codes `MissingArgument` (0x050C) and `ArgTypeMismatch` (0x050D) for component model validation.
- Introduced comments to categorize the new errors under "Component model validation phase".
- Ensured the new error definitions are structured similarly to existing ones, maintaining consistency.

## [include/validator/validator_component.h](https://github.com/WasmEdge/WasmEdge/blob/6d1a39db5dc4ab6b9b76034411e8dd1e30f7df32/include%2Fvalidator%2Fvalidator_component.h)

#### Potential issues

1. **Incorrect Error Handling**: The `matchImportAndArgTypes` function logs errors using `spdlog::error` but does not return an error code for certain mismatch cases, which can lead to inconsistent error handling and potential silent failures.

2. **Unreachable State Logging**: In the `getImports` method, logging for "Unreachable State" is used when an index exceeds component count. This should be replaced with a more robust error handling mechanism, possibly throwing or returning an error code, as this indicates a bug that needs to be addressed.

3. **Incomplete Validation in `matchImportAndArgTypes`**: The function does not handle cases where the sort types are neither `CoreSort` nor `SortCase`. This can lead to incorrect validation results when encountering unsupported sorts, potentially allowing invalid component instantiations.

#### Summary of changes

- **Key Changes:**
- **Added `InstanceExprVisitor` validation**: Includes checks for matching import names and types in `Instantiate` expressions.
- **Introduced `Context` class**: Manages components and provides helper methods to retrieve component details, crucial for validating imports and arguments.
- **Enhanced logging with detailed error messages**: Utilized `spdlog` for more informative error reporting during validation.

## [lib/validator/validator_component.cpp](https://github.com/WasmEdge/WasmEdge/blob/6d1a39db5dc4ab6b9b76034411e8dd1e30f7df32/lib%2Fvalidator%2Fvalidator_component.cpp)

#### Potential issues

1. **Hardcoded Warning Message**: The warning message "component validation is not done yet." should be avoided in production code as it indicates incomplete functionality and can mislead users or developers into thinking the component is validated when it isn't.

2. **Use of `std::literals` without Specific Namespace**: While including `<variant>` and using `using namespace std::literals;` is generally fine, it's better to specify the exact literals namespace (e.g., `using namespace std::string_literals;`) to avoid potential conflicts with other namespaces.

3. **No Validation Logic in Function**: The function `validate` does not contain any actual validation logic for the component sections and instantiate imports/arguments, which is a critical omission given the context of the patch title "[Component Validation] Validate instantiate imports and arguments".

#### Summary of changes

- **Key Changes:**
- Introduced a `Context` object (`Ctx`) to be passed to the `SectionVisitor`.
- Modified `std::visit` call to pass both the validator instance and the new `Context` object to `SectionVisitor`.
- Removed redundant semicolon after the warning log.


author_association: MEMBER
user: login: dannypsnl
created_at: 2025-03-19T00:57:35Z
body: @sridamul We have DCO check, which means for each commit, in message you need to have
```
Signed-off-by: name <email>
```
for example
```
Signed-off-by: Lîm Tsú-thuàn <dannypsnl@secondstate.io>
```
you can use `git commit --signoff` command to do so.
author_association: MEMBER
user: login: codecov[bot]
created_at: 2025-03-19T01:05:18Z
body: ## [Codecov](https://app.codecov.io/gh/WasmEdge/WasmEdge/pull/4062?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge) Report
Attention: Patch coverage is `1.72414%` with `114 lines` in your changes missing coverage. Please review.
> Project coverage is 80.97%. Comparing base [(`e21f40d`)](https://app.codecov.io/gh/WasmEdge/WasmEdge/commit/e21f40dd2fcabf73b4f5e69348655d50ebbde791?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge) to head [(`c643afc`)](https://app.codecov.io/gh/WasmEdge/WasmEdge/commit/c643afc946443a4cf769f3c7e2bbb9530db330c9?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge).
> Report is 1 commits behind head on master.

| [Files with missing lines](https://app.codecov.io/gh/WasmEdge/WasmEdge/pull/4062?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge) | Patch % | Lines |
|---|---|---|
| [include/validator/validator\_component.h](https://app.codecov.io/gh/WasmEdge/WasmEdge/pull/4062?src=pr&el=tree&filepath=include%2Fvalidator%2Fvalidator_component.h&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge#diff-aW5jbHVkZS92YWxpZGF0b3IvdmFsaWRhdG9yX2NvbXBvbmVudC5o) | 0.87% | [113 Missing :warning: ](https://app.codecov.io/gh/WasmEdge/WasmEdge/pull/4062?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge) |
| [lib/validator/validator\_component.cpp](https://app.codecov.io/gh/WasmEdge/WasmEdge/pull/4062?src=pr&el=tree&filepath=lib%2Fvalidator%2Fvalidator_component.cpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge#diff-bGliL3ZhbGlkYXRvci92YWxpZGF0b3JfY29tcG9uZW50LmNwcA==) | 50.00% | [0 Missing and 1 partial :warning: ](https://app.codecov.io/gh/WasmEdge/WasmEdge/pull/4062?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #4062      +/-   ##
==========================================
- Coverage   81.20%   80.97%   -0.24%     
==========================================
  Files         280      280              
  Lines       37916    38029     +113     
  Branches     6466     6518      +52     
==========================================
+ Hits        30790    30794       +4     
- Misses       5538     5647     +109     
  Partials     1588     1588              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/WasmEdge/WasmEdge/pull/4062?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=WasmEdge).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: dannypsnl
created_at: 2025-03-21T08:44:41Z
body: Logic seems correct, let's see CI result.
author_association: MEMBER