Coverage Report

Created: 2025-08-25 06:58

/src/WasmEdge/lib/executor/executor.cpp
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
#include "executor/executor.h"
5
6
#include "common/errinfo.h"
7
#include "common/spdlog.h"
8
#include "system/stacktrace.h"
9
10
using namespace std::literals;
11
12
namespace WasmEdge {
13
namespace Executor {
14
15
/// Instantiate a WASM Module. See "include/executor/executor.h".
16
Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>>
17
Executor::instantiateModule(Runtime::StoreManager &StoreMgr,
18
0
                            const AST::Module &Mod) {
19
0
  return instantiate(StoreMgr, Mod).map_error([this](auto E) {
20
    // If Statistics is enabled, then dump it here.
21
    // When there is an error happened, the following execution will not
22
    // execute.
23
0
    if (Stat) {
24
0
      Stat->dumpToLog(Conf);
25
0
    }
26
0
    return E;
27
0
  });
28
0
}
29
30
/// Register a named WASM module. See "include/executor/executor.h".
31
Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>>
32
Executor::registerModule(Runtime::StoreManager &StoreMgr,
33
0
                         const AST::Module &Mod, std::string_view Name) {
34
0
  return instantiate(StoreMgr, Mod, Name).map_error([this](auto E) {
35
    // If Statistics is enabled, then dump it here.
36
    // When there is an error happened, the following execution will not
37
    // execute.
38
0
    if (Stat) {
39
0
      Stat->dumpToLog(Conf);
40
0
    }
41
0
    return E;
42
0
  });
43
0
}
44
45
/// Register an instantiated module. See "include/executor/executor.h".
46
Expect<void>
47
Executor::registerModule(Runtime::StoreManager &StoreMgr,
48
0
                         const Runtime::Instance::ModuleInstance &ModInst) {
49
0
  return StoreMgr.registerModule(&ModInst).map_error([](auto E) {
50
0
    E = ErrCode::Value::ModuleNameConflict;
51
0
    spdlog::error(E);
52
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
53
0
    return E;
54
0
  });
55
0
}
56
57
/// Instantiate a Component. See "include/executor/executor.h".
58
Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>>
59
Executor::instantiateComponent(Runtime::StoreManager &StoreMgr,
60
0
                               const AST::Component::Component &Comp) {
61
0
  return instantiate(StoreMgr, Comp);
62
0
}
63
64
/// Register a named Component. See "include/executor/executor.h".
65
Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>>
66
Executor::registerComponent(Runtime::StoreManager &StoreMgr,
67
                            const AST::Component::Component &Comp,
68
0
                            std::string_view Name) {
69
0
  return instantiate(StoreMgr, Comp, Name);
70
0
}
71
72
/// Register an instantiated Component. See "include/executor/executor.h".
73
Expect<void> Executor::registerComponent(
74
    Runtime::StoreManager &StoreMgr,
75
0
    const Runtime::Instance::ComponentInstance &CompInst) {
76
0
  return StoreMgr.registerComponent(&CompInst).map_error([](auto E) {
77
0
    E = ErrCode::Value::ModuleNameConflict;
78
0
    spdlog::error(E);
79
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
80
0
    return E;
81
0
  });
82
0
}
83
84
/// Register a host function which will be invoked before calling a
85
/// host function.
86
Expect<void> Executor::registerPreHostFunction(
87
0
    void *HostData = nullptr, std::function<void(void *)> HostFunc = nullptr) {
88
0
  HostFuncHelper.setPreHost(HostData, HostFunc);
89
0
  return {};
90
0
}
91
92
/// Register a host function which will be invoked after calling a
93
/// host function.
94
Expect<void> Executor::registerPostHostFunction(
95
0
    void *HostData = nullptr, std::function<void(void *)> HostFunc = nullptr) {
96
0
  HostFuncHelper.setPostHost(HostData, HostFunc);
97
0
  return {};
98
0
}
99
100
/// Invoke function. See "include/executor/executor.h".
101
Expect<std::vector<std::pair<ValVariant, ValType>>>
102
Executor::invoke(const Runtime::Instance::FunctionInstance *FuncInst,
103
                 Span<const ValVariant> Params,
104
0
                 Span<const ValType> ParamTypes) {
105
0
  if (unlikely(FuncInst == nullptr)) {
106
0
    spdlog::error(ErrCode::Value::FuncNotFound);
107
0
    return Unexpect(ErrCode::Value::FuncNotFound);
108
0
  }
109
110
  // Matching arguments and function type.
111
0
  const auto &FuncType = FuncInst->getFuncType();
112
0
  const auto &PTypes = FuncType.getParamTypes();
113
0
  const auto &RTypes = FuncType.getReturnTypes();
114
  // The defined type list may be empty if the function is an independent
115
  // function instance, that is, the module instance will be nullptr. For this
116
  // case, all of value types are number types or abstract heap types.
117
  //
118
  // If a function belongs to component instance, we should totally get
119
  // converted type, so should no need type list.
120
0
  WasmEdge::Span<const WasmEdge::AST::SubType *const> TypeList = {};
121
0
  if (FuncInst->getModule()) {
122
0
    TypeList = FuncInst->getModule()->getTypeList();
123
0
  }
124
0
  if (!AST::TypeMatcher::matchTypes(TypeList, ParamTypes, PTypes)) {
125
0
    spdlog::error(ErrCode::Value::FuncSigMismatch);
126
0
    spdlog::error(ErrInfo::InfoMismatch(
127
0
        PTypes, RTypes, std::vector(ParamTypes.begin(), ParamTypes.end()),
128
0
        RTypes));
129
0
    return Unexpect(ErrCode::Value::FuncSigMismatch);
130
0
  }
131
132
  // Check the reference value validation.
133
0
  for (uint32_t I = 0; I < ParamTypes.size(); ++I) {
134
0
    if (ParamTypes[I].isRefType() && (!ParamTypes[I].isNullableRefType() &&
135
0
                                      Params[I].get<RefVariant>().isNull())) {
136
0
      spdlog::error(ErrCode::Value::NonNullRequired);
137
0
      spdlog::error("    Cannot pass a null reference as argument of {}."sv,
138
0
                    ParamTypes[I]);
139
0
      return Unexpect(ErrCode::Value::NonNullRequired);
140
0
    }
141
0
  }
142
143
0
  Runtime::StackManager StackMgr;
144
145
  // Call runFunction.
146
0
  EXPECTED_TRY(runFunction(StackMgr, *FuncInst, Params).map_error([](auto E) {
147
0
    if (E != ErrCode::Value::Terminated) {
148
0
      dumpStackTrace(Span<const uint32_t>{StackTrace}.first(StackTraceSize));
149
0
    }
150
0
    return E;
151
0
  }));
152
153
  // Get return values.
154
0
  std::vector<std::pair<ValVariant, ValType>> Returns(RTypes.size());
155
0
  for (uint32_t I = 0; I < RTypes.size(); ++I) {
156
0
    auto Val = StackMgr.pop();
157
0
    const auto &RType = RTypes[RTypes.size() - I - 1];
158
0
    if (RType.isRefType()) {
159
      // For the reference type cases of the return values, they should be
160
      // transformed into abstract heap types due to the opaque of type indices.
161
0
      auto &RefType = Val.get<RefVariant>().getType();
162
0
      if (RefType.isExternalized()) {
163
        // First handle the forced externalized value type case.
164
0
        RefType = ValType(TypeCode::Ref, TypeCode::ExternRef);
165
0
      }
166
0
      if (!RefType.isAbsHeapType()) {
167
        // The instance must not be nullptr because the null references are
168
        // already dynamic typed into the top abstract heap type.
169
0
        auto *Inst =
170
0
            Val.get<RefVariant>().getPtr<Runtime::Instance::CompositeBase>();
171
0
        assuming(Inst);
172
        // The ModInst may be nullptr only in the independent host function
173
        // instance. Therefore the module instance here must not be nullptr
174
        // because the independent host function instance cannot be imported and
175
        // be referred by instructions.
176
0
        const auto *ModInst = Inst->getModule();
177
0
        auto *DefType = *ModInst->getType(RefType.getTypeIndex());
178
0
        RefType =
179
0
            ValType(RefType.getCode(), DefType->getCompositeType().expand());
180
0
      }
181
      // Should use the value type from the reference here due to the dynamic
182
      // typing rule of the null references.
183
0
      Returns[RTypes.size() - I - 1] = std::make_pair(Val, RefType);
184
0
    } else {
185
      // For the number type cases of the return values, the unused bits should
186
      // be erased due to the security issue.
187
0
      cleanNumericVal(Val, RType);
188
0
      Returns[RTypes.size() - I - 1] = std::make_pair(Val, RType);
189
0
    }
190
0
  }
191
192
  // After execution, the value stack size should be 0.
193
0
  assuming(StackMgr.size() == 0);
194
0
  return Returns;
195
0
}
196
197
/// Async invoke function. See "include/executor/executor.h".
198
Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
199
Executor::asyncInvoke(const Runtime::Instance::FunctionInstance *FuncInst,
200
                      Span<const ValVariant> Params,
201
0
                      Span<const ValType> ParamTypes) {
202
0
  Expect<std::vector<std::pair<ValVariant, ValType>>> (Executor::*FPtr)(
203
0
      const Runtime::Instance::FunctionInstance *, Span<const ValVariant>,
204
0
      Span<const ValType>) = &Executor::invoke;
205
0
  return {FPtr, *this, FuncInst, std::vector(Params.begin(), Params.end()),
206
0
          std::vector(ParamTypes.begin(), ParamTypes.end())};
207
0
}
208
209
/// Invoke component function. See "include/executor/executor.h".
210
Expect<std::vector<std::pair<ValInterface, ValType>>>
211
Executor::invoke(const Runtime::Instance::Component::FunctionInstance *FuncInst,
212
                 Span<const ValInterface> Params,
213
0
                 Span<const ValType> ParamTypes) {
214
  // NOTE: due to internal reason, we accept the multi-return values, but in
215
  // fact a component function will only return at most one. This concept
216
  // mismatching should be fix in the future.
217
0
  if (unlikely(FuncInst == nullptr)) {
218
0
    spdlog::error(ErrCode::Value::FuncNotFound);
219
0
    return Unexpect(ErrCode::Value::FuncNotFound);
220
0
  }
221
222
  // Matching arguments and function type.
223
0
  const auto &FuncType = FuncInst->getFuncType();
224
0
  const auto &PTypes = FuncType.getParamTypes();
225
0
  const auto &RTypes = FuncType.getReturnTypes();
226
227
0
  Span<const WasmEdge::AST::SubType *const> TypeList = {};
228
0
  if (!AST::TypeMatcher::matchTypes(TypeList, ParamTypes, PTypes)) {
229
0
    spdlog::error(ErrCode::Value::FuncSigMismatch);
230
0
    spdlog::error(ErrInfo::InfoMismatch(
231
0
        PTypes, RTypes, std::vector(ParamTypes.begin(), ParamTypes.end()),
232
0
        RTypes));
233
0
    return Unexpect(ErrCode::Value::FuncSigMismatch);
234
0
  }
235
236
0
  auto &HostFunc = FuncInst->getHostFunc();
237
0
  std::vector<ValInterface> Rets(RTypes.size());
238
239
0
  EXPECTED_TRY(HostFunc.run(std::move(Params), Rets));
240
241
0
  std::vector<std::pair<ValInterface, ValType>> R;
242
0
  auto RType = RTypes.begin();
243
0
  for (auto &&V : Rets) {
244
0
    R.push_back(std::pair(V, *RType));
245
0
    RType++;
246
0
  }
247
0
  return R;
248
0
}
249
250
} // namespace Executor
251
} // namespace WasmEdge