Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/executor/instantiate/import.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "executor/executor.h"
5
6
#include "common/errinfo.h"
7
#include "common/spdlog.h"
8
9
#include <cstdint>
10
#include <string_view>
11
#include <utility>
12
13
using namespace std::literals;
14
15
namespace WasmEdge {
16
namespace Executor {
17
18
namespace {
19
template <typename... Args>
20
auto logMatchError(std::string_view ModName, std::string_view ExtName,
21
0
                   ExternalType ExtType, Args &&...Values) {
22
0
  spdlog::error(ErrCode::Value::IncompatibleImportType);
23
0
  spdlog::error(ErrInfo::InfoMismatch(std::forward<Args>(Values)...));
24
0
  spdlog::error(ErrInfo::InfoLinking(ModName, ExtName, ExtType));
25
0
  spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Import));
26
0
  return Unexpect(ErrCode::Value::IncompatibleImportType);
27
0
}
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::(anonymous namespace)::logMatchError<WasmEdge::ExternalType const&, WasmEdge::ExternalType>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::ExternalType, WasmEdge::ExternalType const&, WasmEdge::ExternalType&&)
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::(anonymous namespace)::logMatchError<std::__1::vector<WasmEdge::ValType, std::__1::allocator<WasmEdge::ValType> > const&, std::__1::vector<WasmEdge::ValType, std::__1::allocator<WasmEdge::ValType> > const&, std::__1::vector<WasmEdge::ValType, std::__1::allocator<WasmEdge::ValType> > const&, std::__1::vector<WasmEdge::ValType, std::__1::allocator<WasmEdge::ValType> > const&>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::ExternalType, std::__1::vector<WasmEdge::ValType, std::__1::allocator<WasmEdge::ValType> > const&, std::__1::vector<WasmEdge::ValType, std::__1::allocator<WasmEdge::ValType> > const&, std::__1::vector<WasmEdge::ValType, std::__1::allocator<WasmEdge::ValType> > const&, std::__1::vector<WasmEdge::ValType, std::__1::allocator<WasmEdge::ValType> > const&)
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::(anonymous namespace)::logMatchError<WasmEdge::ValType const&, bool, unsigned long, unsigned long, WasmEdge::ValType const&, bool, unsigned long, unsigned long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::ExternalType, WasmEdge::ValType const&, bool&&, unsigned long&&, unsigned long&&, WasmEdge::ValType const&, bool&&, unsigned long&&, unsigned long&&)
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::(anonymous namespace)::logMatchError<bool, unsigned long, unsigned long, bool, unsigned long, unsigned long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::ExternalType, bool&&, unsigned long&&, unsigned long&&, bool&&, unsigned long&&, unsigned long&&)
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::(anonymous namespace)::logMatchError<WasmEdge::ValType const&, WasmEdge::ValMut, WasmEdge::ValType const&, WasmEdge::ValMut>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::ExternalType, WasmEdge::ValType const&, WasmEdge::ValMut&&, WasmEdge::ValType const&, WasmEdge::ValMut&&)
28
29
auto logUnknownError(std::string_view ModName, std::string_view ExtName,
30
0
                     ExternalType ExtType) {
31
0
  spdlog::error(ErrCode::Value::UnknownImport);
32
0
  spdlog::error(ErrInfo::InfoLinking(ModName, ExtName, ExtType));
33
0
  spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Desc_Import));
34
0
  return Unexpect(ErrCode::Value::UnknownImport);
35
0
}
36
37
Expect<void>
38
checkImportMatched(std::string_view ModName, std::string_view ExtName,
39
                   const ExternalType ExtType,
40
0
                   const Runtime::Instance::ModuleInstance &ModInst) {
41
0
  switch (ExtType) {
42
0
  case ExternalType::Function:
43
0
    if (auto Res = ModInst.findFuncExports(ExtName); likely(Res != nullptr)) {
44
0
      return {};
45
0
    }
46
0
    break;
47
0
  case ExternalType::Table:
48
0
    if (auto Res = ModInst.findTableExports(ExtName); likely(Res != nullptr)) {
49
0
      return {};
50
0
    }
51
0
    break;
52
0
  case ExternalType::Memory:
53
0
    if (auto Res = ModInst.findMemoryExports(ExtName); likely(Res != nullptr)) {
54
0
      return {};
55
0
    }
56
0
    break;
57
0
  case ExternalType::Global:
58
0
    if (auto Res = ModInst.findGlobalExports(ExtName); likely(Res != nullptr)) {
59
0
      return {};
60
0
    }
61
0
    break;
62
0
  case ExternalType::Tag:
63
0
    if (auto Res = ModInst.findTagExports(ExtName); likely(Res != nullptr)) {
64
0
      return {};
65
0
    }
66
0
    break;
67
0
  default:
68
0
    assumingUnreachable();
69
0
  }
70
71
  // Check for error external types or unknown imports.
72
0
  if (ModInst.findFuncExports(ExtName)) {
73
0
    return logMatchError(ModName, ExtName, ExtType, ExtType,
74
0
                         ExternalType::Function);
75
0
  }
76
0
  if (ModInst.findTableExports(ExtName)) {
77
0
    return logMatchError(ModName, ExtName, ExtType, ExtType,
78
0
                         ExternalType::Table);
79
0
  }
80
0
  if (ModInst.findMemoryExports(ExtName)) {
81
0
    return logMatchError(ModName, ExtName, ExtType, ExtType,
82
0
                         ExternalType::Memory);
83
0
  }
84
0
  if (ModInst.findTagExports(ExtName)) {
85
0
    return logMatchError(ModName, ExtName, ExtType, ExtType, ExternalType::Tag);
86
0
  }
87
0
  if (ModInst.findGlobalExports(ExtName)) {
88
0
    return logMatchError(ModName, ExtName, ExtType, ExtType,
89
0
                         ExternalType::Global);
90
0
  }
91
92
0
  return logUnknownError(ModName, ExtName, ExtType);
93
0
}
94
} // namespace
95
96
// Instantiate imports. See "include/executor/executor.h".
97
Expect<void> Executor::instantiate(
98
    std::function<const Runtime::Instance::ModuleInstance *(std::string_view)>
99
        ModuleFinder,
100
    Runtime::Instance::ModuleInstance &ModInst,
101
0
    const AST::ImportSection &ImportSec) {
102
  // Pairs of recursive types found equal, shared by the imports.
103
0
  AST::TypeMatcher::RecTypePairs Equal;
104
  // Iterate and instantiate import descriptions.
105
0
  for (const auto &ImpDesc : ImportSec.getContent()) {
106
    // Get data from import description and find import module.
107
0
    auto ExtType = ImpDesc.getExternalType();
108
0
    auto ModName = ImpDesc.getModuleName();
109
0
    auto ExtName = ImpDesc.getExternalName();
110
0
    const auto *ImpModInst = ModuleFinder(ModName);
111
0
    if (unlikely(ImpModInst == nullptr)) {
112
0
      auto Res = logUnknownError(ModName, ExtName, ExtType);
113
0
      if (ModName == "wasi_snapshot_preview1"sv) {
114
0
        spdlog::error("    This is a WASI related import. Please ensure that "
115
0
                      "you've turned on the WASI configuration."sv);
116
0
      } else if (ModName == "wasi_nn"sv) {
117
0
        spdlog::error("    This is a WASI-NN related import. Please ensure "
118
0
                      "that you've turned on the WASI-NN configuration and "
119
0
                      "installed the WASI-NN plug-in."sv);
120
0
      } else if (ModName == "wasi_crypto_common"sv ||
121
0
                 ModName == "wasi_crypto_asymmetric_common"sv ||
122
0
                 ModName == "wasi_crypto_kx"sv ||
123
0
                 ModName == "wasi_crypto_signatures"sv ||
124
0
                 ModName == "wasi_crypto_symmetric"sv) {
125
0
        spdlog::error("    This is a WASI-Crypto related import. Please ensure "
126
0
                      "that you've turned on the WASI-Crypto configuration and "
127
0
                      "installed the WASI-Crypto plug-in."sv);
128
0
      } else if (ModName == "env"sv) {
129
0
        spdlog::error(
130
0
            "    This may be the import of host environment like JavaScript or "
131
0
            "Golang. Please check that you've registered the necessary host "
132
0
            "modules from the host programming language."sv);
133
0
      }
134
0
      return Res;
135
0
    }
136
0
    EXPECTED_TRY(checkImportMatched(ModName, ExtName, ExtType, *ImpModInst));
137
    // Read the types of an instance from its defining module, if any.
138
0
    auto GetImpTypeList = [&ImpModInst](const auto *Inst) {
139
0
      return Inst->getModule() ? Inst->getModule()->getTypeList()
140
0
                               : ImpModInst->getTypeList();
141
0
    };
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::Executor::instantiate(std::__1::function<WasmEdge::Runtime::Instance::ModuleInstance const* (std::__1::basic_string_view<char, std::__1::char_traits<char> >)>, WasmEdge::Runtime::Instance::ModuleInstance&, WasmEdge::AST::ImportSection const&)::$_0::operator()<WasmEdge::Runtime::Instance::FunctionInstance>(WasmEdge::Runtime::Instance::FunctionInstance const*) const
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::Executor::instantiate(std::__1::function<WasmEdge::Runtime::Instance::ModuleInstance const* (std::__1::basic_string_view<char, std::__1::char_traits<char> >)>, WasmEdge::Runtime::Instance::ModuleInstance&, WasmEdge::AST::ImportSection const&)::$_0::operator()<WasmEdge::Runtime::Instance::TableInstance>(WasmEdge::Runtime::Instance::TableInstance const*) const
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::Executor::instantiate(std::__1::function<WasmEdge::Runtime::Instance::ModuleInstance const* (std::__1::basic_string_view<char, std::__1::char_traits<char> >)>, WasmEdge::Runtime::Instance::ModuleInstance&, WasmEdge::AST::ImportSection const&)::$_0::operator()<WasmEdge::Runtime::Instance::TagInstance>(WasmEdge::Runtime::Instance::TagInstance const*) const
Unexecuted instantiation: import.cpp:auto WasmEdge::Executor::Executor::instantiate(std::__1::function<WasmEdge::Runtime::Instance::ModuleInstance const* (std::__1::basic_string_view<char, std::__1::char_traits<char> >)>, WasmEdge::Runtime::Instance::ModuleInstance&, WasmEdge::AST::ImportSection const&)::$_0::operator()<WasmEdge::Runtime::Instance::GlobalInstance>(WasmEdge::Runtime::Instance::GlobalInstance const*) const
142
143
    // Add the imports to the module instance.
144
0
    switch (ExtType) {
145
0
    case ExternalType::Function: {
146
      // Get the function type index. The external type is checked in
147
      // validation.
148
0
      uint32_t TypeIdx = ImpDesc.getExternalFuncTypeIdx();
149
      // Import matching.
150
0
      auto *ImpInst = ImpModInst->findFuncExports(ExtName);
151
0
      if (!AST::TypeMatcher::matchType(ModInst.getTypeList(), TypeIdx,
152
0
                                       GetImpTypeList(ImpInst),
153
0
                                       ImpInst->getTypeIndex(), &Equal)) {
154
0
        const auto &ExpDefType = **ModInst.getType(TypeIdx);
155
0
        bool IsMatchV2 = false;
156
0
        const auto &ExpFuncType = ExpDefType.getCompositeType().getFuncType();
157
0
        const auto &ImpFuncType = ImpInst->getFuncType();
158
0
        if (ModName == "wasi_snapshot_preview1"sv) {
159
          /*
160
           * The following functions should provide V1 and V2.
161
             "sock_open_v2",
162
             "sock_bind_v2",
163
             "sock_connect_v2",
164
             "sock_listen_v2",
165
             "sock_accept_v2",
166
             "sock_recv_v2",
167
             "sock_recv_from_v2",
168
             "sock_send_v2",
169
             "sock_send_to_v2",
170
             "sock_getlocaladdr_v2",
171
             "sock_getpeeraddr_v2"
172
             */
173
0
          std::vector<std::string_view> CompatibleWASISocketAPI = {
174
0
              "sock_open"sv,         "sock_bind"sv,       "sock_connect"sv,
175
0
              "sock_listen"sv,       "sock_accept"sv,     "sock_recv"sv,
176
0
              "sock_recv_from"sv,    "sock_send"sv,       "sock_send_to"sv,
177
0
              "sock_getlocaladdr"sv, "sock_getpeeraddr"sv};
178
0
          for (auto Iter = CompatibleWASISocketAPI.begin();
179
0
               Iter != CompatibleWASISocketAPI.end(); Iter++) {
180
0
            if (ExtName == *Iter) {
181
0
              auto *ImpInstV2 =
182
0
                  ImpModInst->findFuncExports(std::string(*Iter) + "_v2");
183
0
              if (ImpInstV2 != nullptr &&
184
0
                  AST::TypeMatcher::matchType(
185
0
                      ModInst.getTypeList(), TypeIdx, GetImpTypeList(ImpInstV2),
186
0
                      ImpInstV2->getTypeIndex(), &Equal)) {
187
                // Try to match the new version
188
0
                ImpInst = ImpInstV2;
189
0
                IsMatchV2 = true;
190
0
                break;
191
0
              }
192
0
            }
193
0
          }
194
0
        }
195
0
        if (!IsMatchV2) {
196
0
          return logMatchError(
197
0
              ModName, ExtName, ExtType, ExpFuncType.getParamTypes(),
198
0
              ExpFuncType.getReturnTypes(), ImpFuncType.getParamTypes(),
199
0
              ImpFuncType.getReturnTypes());
200
0
        }
201
0
      }
202
      // Set the matched function address in the module instance.
203
0
      ModInst.importFunction(ImpInst);
204
205
      // If the imported function is a WASI function, mark it in the module.
206
0
      if (!ModInst.getWASIModule() && ModName == "wasi_snapshot_preview1"sv) {
207
0
        ModInst.setWASIModule(ImpModInst);
208
0
      }
209
0
      break;
210
0
    }
211
0
    case ExternalType::Table: {
212
      // Get table type. External type checked in validation.
213
0
      const auto &TabType = ImpDesc.getExternalTableType();
214
0
      const auto &TabLim = TabType.getLimit();
215
      // Import matching. External table type should match the one in import
216
      // description.
217
0
      auto *ImpInst = ImpModInst->findTableExports(ExtName);
218
0
      const auto &ImpType = ImpInst->getTableType();
219
0
      const auto &ImpLim = ImpType.getLimit();
220
0
      if (!AST::TypeMatcher::matchType(ModInst.getTypeList(), TabType,
221
0
                                       GetImpTypeList(ImpInst), ImpType,
222
0
                                       &Equal)) {
223
0
        return logMatchError(ModName, ExtName, ExtType, TabType.getRefType(),
224
0
                             TabLim.hasMax(), TabLim.getMin(), TabLim.getMax(),
225
0
                             ImpType.getRefType(), ImpLim.hasMax(),
226
0
                             ImpLim.getMin(), ImpLim.getMax());
227
0
      }
228
      // Set the matched table address in the module instance.
229
0
      ModInst.importTable(ImpInst);
230
0
      break;
231
0
    }
232
0
    case ExternalType::Memory: {
233
      // Get memory type. External type checked in validation.
234
0
      const auto &MemType = ImpDesc.getExternalMemoryType();
235
0
      const auto &MemLim = MemType.getLimit();
236
      // Import matching. External memory type should match the one in import
237
      // description.
238
0
      auto *ImpInst = ImpModInst->findMemoryExports(ExtName);
239
0
      const auto &ImpLim = ImpInst->getMemoryType().getLimit();
240
0
      if (!AST::TypeMatcher::matchLimit(MemLim, ImpLim)) {
241
0
        return logMatchError(ModName, ExtName, ExtType, MemLim.hasMax(),
242
0
                             MemLim.getMin(), MemLim.getMax(), ImpLim.hasMax(),
243
0
                             ImpLim.getMin(), ImpLim.getMax());
244
0
      }
245
      // Set the matched memory address in the module instance.
246
0
      ModInst.importMemory(ImpInst);
247
0
      break;
248
0
    }
249
0
    case ExternalType::Tag: {
250
      // Get tag type. External type checked in validation.
251
0
      const auto &TagType = ImpDesc.getExternalTagType();
252
      // Import matching.
253
0
      auto *ImpInst = ImpModInst->findTagExports(ExtName);
254
0
      if (!AST::TypeMatcher::matchType(ModInst.getTypeList(), TagType,
255
0
                                       GetImpTypeList(ImpInst),
256
0
                                       ImpInst->getTagType(), &Equal)) {
257
0
        const auto &ExpFuncType =
258
0
            TagType.getDefType().getCompositeType().getFuncType();
259
0
        const auto &ImpFuncType =
260
0
            ImpInst->getTagType().getDefType().getCompositeType().getFuncType();
261
0
        return logMatchError(
262
0
            ModName, ExtName, ExtType, ExpFuncType.getParamTypes(),
263
0
            ExpFuncType.getReturnTypes(), ImpFuncType.getParamTypes(),
264
0
            ImpFuncType.getReturnTypes());
265
0
      }
266
0
      ModInst.importTag(ImpInst);
267
0
      break;
268
0
    }
269
0
    case ExternalType::Global: {
270
      // Get global type. External type checked in validation.
271
0
      const auto &GlobType = ImpDesc.getExternalGlobalType();
272
      // Import matching. External global type should match the one in
273
      // import description.
274
0
      auto *ImpInst = ImpModInst->findGlobalExports(ExtName);
275
0
      const auto &ImpType = ImpInst->getGlobalType();
276
0
      if (!AST::TypeMatcher::matchType(ModInst.getTypeList(), GlobType,
277
0
                                       GetImpTypeList(ImpInst), ImpType,
278
0
                                       &Equal)) {
279
0
        return logMatchError(ModName, ExtName, ExtType, GlobType.getValType(),
280
0
                             GlobType.getValMut(), ImpType.getValType(),
281
0
                             ImpType.getValMut());
282
0
      }
283
      // Set the matched global address in the module instance.
284
0
      ModInst.importGlobal(ImpInst);
285
0
      break;
286
0
    }
287
0
    default:
288
0
      assumingUnreachable();
289
0
    }
290
0
  }
291
0
  return {};
292
0
}
293
294
} // namespace Executor
295
} // namespace WasmEdge