GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_wasi.cc Lines: 469 580 80.9 %
Date: 2022-12-31 04:22:30 Branches: 143 282 50.7 %

Line Branch Exec Source
1
#include "env-inl.h"
2
#include "base_object-inl.h"
3
#include "debug_utils-inl.h"
4
#include "memory_tracker-inl.h"
5
#include "node_mem-inl.h"
6
#include "util-inl.h"
7
#include "node.h"
8
#include "node_errors.h"
9
#include "uv.h"
10
#include "uvwasi.h"
11
#include "node_wasi.h"
12
13
namespace node {
14
namespace wasi {
15
16
template <typename... Args>
17
682
inline void Debug(const WASI& wasi, Args&&... args) {
18
682
  Debug(wasi.env(), DebugCategory::WASI, std::forward<Args>(args)...);
19
}
20
21
#define CHECK_BOUNDS_OR_RETURN(mem_size, offset, buf_size)                     \
22
  do {                                                                         \
23
    if (!uvwasi_serdes_check_bounds((offset), (mem_size), (buf_size))) {       \
24
      return UVWASI_EOVERFLOW;                                                 \
25
    }                                                                          \
26
  } while (0)
27
28
using v8::Array;
29
using v8::ArrayBuffer;
30
using v8::BigInt;
31
using v8::CFunction;
32
using v8::Context;
33
using v8::Exception;
34
using v8::FastApiCallbackOptions;
35
using v8::FunctionCallbackInfo;
36
using v8::FunctionTemplate;
37
using v8::Integer;
38
using v8::Isolate;
39
using v8::Local;
40
using v8::MaybeLocal;
41
using v8::Object;
42
using v8::Signature;
43
using v8::String;
44
using v8::Uint32;
45
using v8::Value;
46
using v8::WasmMemoryObject;
47
48
1
static MaybeLocal<Value> WASIException(Local<Context> context,
49
                                       int errorno,
50
                                       const char* syscall) {
51
1
  Isolate* isolate = context->GetIsolate();
52
1
  Environment* env = Environment::GetCurrent(context);
53
1
  CHECK_NOT_NULL(env);
54
1
  const char* err_name = uvwasi_embedder_err_code_to_string(errorno);
55
1
  Local<String> js_code = OneByteString(isolate, err_name);
56
1
  Local<String> js_syscall = OneByteString(isolate, syscall);
57
1
  Local<String> js_msg = js_code;
58
  js_msg =
59
1
      String::Concat(isolate, js_msg, FIXED_ONE_BYTE_STRING(isolate, ", "));
60
1
  js_msg = String::Concat(isolate, js_msg, js_syscall);
61
  Local<Object> e;
62
3
  if (!Exception::Error(js_msg)->ToObject(context).ToLocal(&e))
63
    return MaybeLocal<Value>();
64
65
2
  if (e->Set(context,
66
             env->errno_string(),
67
3
             Integer::New(isolate, errorno)).IsNothing() ||
68

5
      e->Set(context, env->code_string(), js_code).IsNothing() ||
69

4
      e->Set(context, env->syscall_string(), js_syscall).IsNothing()) {
70
    return MaybeLocal<Value>();
71
  }
72
73
1
  return e;
74
}
75
76
77
65
WASI::WASI(Environment* env,
78
           Local<Object> object,
79
65
           uvwasi_options_t* options) : BaseObject(env, object) {
80
65
  MakeWeak();
81
65
  alloc_info_ = MakeAllocator();
82
65
  options->allocator = &alloc_info_;
83
65
  int err = uvwasi_init(&uvw_, options);
84
65
  if (err != UVWASI_ESUCCESS) {
85
    Local<Value> exception;
86
2
    if (!WASIException(env->context(), err, "uvwasi_init").ToLocal(&exception))
87
      return;
88
89
1
    env->isolate()->ThrowException(exception);
90
  }
91
}
92
93
94
378
WASI::~WASI() {
95
126
  uvwasi_destroy(&uvw_);
96
126
  CHECK_EQ(current_uvwasi_memory_, 0);
97
252
}
98
99
void WASI::MemoryInfo(MemoryTracker* tracker) const {
100
  tracker->TrackField("memory", memory_);
101
  tracker->TrackFieldWithSize("uvwasi_memory", current_uvwasi_memory_);
102
}
103
104
1905
void WASI::CheckAllocatedSize(size_t previous_size) const {
105
1905
  CHECK_GE(current_uvwasi_memory_, previous_size);
106
1905
}
107
108
987
void WASI::IncreaseAllocatedSize(size_t size) {
109
987
  current_uvwasi_memory_ += size;
110
987
}
111
112
918
void WASI::DecreaseAllocatedSize(size_t size) {
113
918
  current_uvwasi_memory_ -= size;
114
918
}
115
116
65
void WASI::New(const FunctionCallbackInfo<Value>& args) {
117
65
  CHECK(args.IsConstructCall());
118
65
  CHECK_EQ(args.Length(), 4);
119
65
  CHECK(args[0]->IsArray());
120
65
  CHECK(args[1]->IsArray());
121
65
  CHECK(args[2]->IsArray());
122
65
  CHECK(args[3]->IsArray());
123
124
65
  Environment* env = Environment::GetCurrent(args);
125
65
  Local<Context> context = env->context();
126
130
  Local<Array> argv = args[0].As<Array>();
127
65
  const uint32_t argc = argv->Length();
128
  uvwasi_options_t options;
129
130
65
  uvwasi_options_init(&options);
131
132
130
  Local<Array> stdio = args[3].As<Array>();
133
65
  CHECK_EQ(stdio->Length(), 3);
134
130
  options.in = stdio->Get(context, 0).ToLocalChecked()->
135
130
    Int32Value(context).FromJust();
136
130
  options.out = stdio->Get(context, 1).ToLocalChecked()->
137
130
    Int32Value(context).FromJust();
138
130
  options.err = stdio->Get(context, 2).ToLocalChecked()->
139
65
    Int32Value(context).FromJust();
140
141
65
  options.fd_table_size = 3;
142
65
  options.argc = argc;
143
65
  options.argv =
144
65
    const_cast<const char**>(argc == 0 ? nullptr : new char*[argc]);
145
146
182
  for (uint32_t i = 0; i < argc; i++) {
147
234
    auto arg = argv->Get(context, i).ToLocalChecked();
148
234
    CHECK(arg->IsString());
149
234
    node::Utf8Value str(env->isolate(), arg);
150
117
    options.argv[i] = strdup(*str);
151
117
    CHECK_NOT_NULL(options.argv[i]);
152
  }
153
154
130
  Local<Array> env_pairs = args[1].As<Array>();
155
65
  const uint32_t envc = env_pairs->Length();
156
65
  options.envp = const_cast<const char**>(new char*[envc + 1]);
157
3414
  for (uint32_t i = 0; i < envc; i++) {
158
6698
    auto pair = env_pairs->Get(context, i).ToLocalChecked();
159
6698
    CHECK(pair->IsString());
160
6698
    node::Utf8Value str(env->isolate(), pair);
161
3349
    options.envp[i] = strdup(*str);
162
3349
    CHECK_NOT_NULL(options.envp[i]);
163
  }
164
65
  options.envp[envc] = nullptr;
165
166
130
  Local<Array> preopens = args[2].As<Array>();
167
65
  CHECK_EQ(preopens->Length() % 2, 0);
168
65
  options.preopenc = preopens->Length() / 2;
169
65
  options.preopens = Calloc<uvwasi_preopen_t>(options.preopenc);
170
65
  int index = 0;
171
304
  for (uint32_t i = 0; i < preopens->Length(); i += 2) {
172
174
    auto mapped = preopens->Get(context, i).ToLocalChecked();
173
174
    auto real = preopens->Get(context, i + 1).ToLocalChecked();
174
174
    CHECK(mapped->IsString());
175
174
    CHECK(real->IsString());
176
174
    node::Utf8Value mapped_path(env->isolate(), mapped);
177
87
    node::Utf8Value real_path(env->isolate(), real);
178
87
    options.preopens[index].mapped_path = strdup(*mapped_path);
179
87
    CHECK_NOT_NULL(options.preopens[index].mapped_path);
180
87
    options.preopens[index].real_path = strdup(*real_path);
181
87
    CHECK_NOT_NULL(options.preopens[index].real_path);
182
87
    index++;
183
  }
184
185
65
  new WASI(env, args.This(), &options);
186
187
65
  if (options.argv != nullptr) {
188
156
    for (uint32_t i = 0; i < argc; i++)
189
117
      free(const_cast<char*>(options.argv[i]));
190
39
    delete[] options.argv;
191
  }
192
193
3414
  for (uint32_t i = 0; options.envp[i]; i++)
194
3349
    free(const_cast<char*>(options.envp[i]));
195
65
  delete[] options.envp;
196
197
65
  if (options.preopens != nullptr) {
198
131
    for (uint32_t i = 0; i < options.preopenc; i++) {
199
87
      free(const_cast<char*>(options.preopens[i].mapped_path));
200
87
      free(const_cast<char*>(options.preopens[i].real_path));
201
    }
202
203
44
    free(options.preopens);
204
  }
205
65
}
206
207
template <typename FT, FT F, typename R, typename... Args>
208
4680
void WASI::WasiFunction<FT, F, R, Args...>::SetFunction(
209
    Environment* env, const char* name, Local<FunctionTemplate> tmpl) {
210
4680
  auto c_function = CFunction::Make(FastCallback);
211
  Local<FunctionTemplate> t =
212
4680
      FunctionTemplate::New(env->isolate(),
213
                            SlowCallback,
214
                            Local<Value>(),
215
                            Local<Signature>(),
216
                            sizeof...(Args),
217
                            v8::ConstructorBehavior::kThrow,
218
                            v8::SideEffectType::kHasSideEffect,
219
                            &c_function);
220
4680
  const v8::NewStringType type = v8::NewStringType::kInternalized;
221
  Local<String> name_string =
222
9360
      String::NewFromUtf8(env->isolate(), name, type).ToLocalChecked();
223
9360
  tmpl->PrototypeTemplate()->Set(name_string, t);
224
4680
  t->SetClassName(name_string);
225
4680
}
226
227
namespace {
228
template <typename R>
229
inline R EinvalError();
230
231
template <>
232
1
inline uint32_t EinvalError() {
233
1
  return UVWASI_EINVAL;
234
}
235
236
template <>
237
inline void EinvalError() {}
238
}  // namespace
239
240
template <typename FT, FT F, typename R, typename... Args>
241
394
R WASI::WasiFunction<FT, F, R, Args...>::FastCallback(
242
    Local<Object> receiver,
243
    Args... args,
244
    // NOLINTNEXTLINE(runtime/references) This is V8 api.
245
    FastApiCallbackOptions& options) {
246
394
  WASI* wasi = reinterpret_cast<WASI*>(BaseObject::FromJSObject(receiver));
247
394
  if (UNLIKELY(wasi == nullptr)) return EinvalError<R>();
248
249

394
  if (UNLIKELY(options.wasm_memory == nullptr || wasi->memory_.IsEmpty())) {
250
    // fallback to slow path which to throw an error about missing memory.
251
2
    options.fallback = true;
252
2
    return EinvalError<R>();
253
  }
254
392
  uint8_t* memory = nullptr;
255

392
  CHECK(LIKELY(options.wasm_memory->getStorageIfAligned(&memory)));
256
257
392
  return F(*wasi,
258
392
           {reinterpret_cast<char*>(memory), options.wasm_memory->length()},
259
390
           args...);
260
}
261
262
namespace {
263
template <typename VT>
264
static bool CheckType(Local<Value> v);
265
266
template <typename VT>
267
static VT ConvertType(Local<Value> V);
268
269
template <>
270
425
bool CheckType<uint32_t>(Local<Value> value) {
271
425
  return value->IsUint32();
272
}
273
274
template <>
275
422
uint32_t ConvertType(Local<Value> value) {
276
422
  return value.As<Uint32>()->Value();
277
}
278
279
template <>
280
36
bool CheckType<uint64_t>(Local<Value> value) {
281
36
  return value->IsBigInt();
282
}
283
284
template <>
285
36
uint64_t ConvertType(Local<Value> value) {
286
36
  Local<BigInt> js_value = value.As<BigInt>();
287
  bool lossless;
288
36
  return js_value->Uint64Value(&lossless);
289
}
290
291
template <>
292
1
bool CheckType<int64_t>(Local<Value> value) {
293
1
  return value->IsBigInt();
294
}
295
296
template <>
297
1
int64_t ConvertType(Local<Value> value) {
298
1
  Local<BigInt> js_value = value.As<BigInt>();
299
  bool lossless;
300
1
  return js_value->Int64Value(&lossless);
301
}
302
303
template <typename T>
304
924
bool CheckTypes(const FunctionCallbackInfo<Value>& info, int i, T) {
305
924
  return CheckType<T>(info[i]);
306
}
307
308
template <typename T, typename... Ts>
309
630
bool CheckTypes(const FunctionCallbackInfo<Value>& info,
310
                int i,
311
                T arg,
312
                Ts... args) {
313
630
  if (!CheckTypes<T>(info, i, arg)) return false;
314
630
  return CheckTypes<Ts...>(info, i + 1, args...);
315
}
316
317
template <typename... Args>
318
294
bool CheckTypes(const FunctionCallbackInfo<Value>& info) {
319
294
  return CheckTypes<Args...>(info, 0, Args()...);
320
}
321
322
template <>
323
bool CheckTypes(const FunctionCallbackInfo<Value>& info) {
324
  return true;
325
}
326
327
template <typename FT,
328
          FT F,
329
          typename R,
330
          typename... Args,
331
          std::size_t... Indices,
332
          typename std::enable_if_t<!std::is_void<R>::value, bool> = true>
333
288
inline void CallAndSetReturn(std::index_sequence<Indices...>,
334
                             const FunctionCallbackInfo<Value>& args,
335
                             WASI* wasi,
336
                             WasmMemory memory) {
337
1204
  args.GetReturnValue().Set(
338
      F(*wasi, memory, ConvertType<Args>(args[Indices])...));
339
}
340
341
template <typename FT,
342
          FT F,
343
          typename R,
344
          typename... Args,
345
          std::size_t... Indices,
346
          typename std::enable_if_t<std::is_void<R>::value, bool> = true>
347
1
inline void CallAndSetReturn(std::index_sequence<Indices...>,
348
                             const FunctionCallbackInfo<Value>& args,
349
                             WASI* wasi,
350
                             WasmMemory memory) {
351
1
  F(*wasi, memory, ConvertType<Args>(args[Indices])...);
352
}
353
354
}  // namespace
355
356
template <typename FT, FT F, typename R, typename... Args>
357
294
void WASI::WasiFunction<FT, F, R, Args...>::SlowCallback(
358
    const FunctionCallbackInfo<Value>& args) {
359
294
  if (args.Length() != sizeof...(Args)) {
360
    args.GetReturnValue().Set(UVWASI_EINVAL);
361
4
    return;
362
  }
363
294
  if (!CheckTypes<Args...>(args)) {
364
2
    args.GetReturnValue().Set(UVWASI_EINVAL);
365
2
    return;
366
  }
367
368
  WASI* wasi;
369
292
  ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This());
370
292
  if (wasi->memory_.IsEmpty()) {
371
2
    THROW_ERR_WASI_NOT_STARTED(Environment::GetCurrent(args));
372
2
    return;
373
  }
374
375
290
  Local<WasmMemoryObject> memory = PersistentToLocal::Strong(wasi->memory_);
376
290
  Local<ArrayBuffer> ab = memory->Buffer();
377
290
  size_t mem_size = ab->ByteLength();
378
290
  char* mem_data = static_cast<char*>(ab->Data());
379
290
  CHECK_NOT_NULL(mem_data);
380
381
290
  CallAndSetReturn<FT, F, R, Args...>(
382
      std::make_index_sequence<sizeof...(Args)>{},
383
      args,
384
      wasi,
385
      {mem_data, mem_size});
386
}
387
388
template <typename FT, FT F, typename R, typename... Args>
389
4680
static void SetFunction(R (*f)(WASI&, WasmMemory, Args...),
390
                        Environment* env,
391
                        const char* name,
392
                        Local<FunctionTemplate> tmpl) {
393
4680
  WASI::WasiFunction<FT, F, R, Args...>::SetFunction(env, name, tmpl);
394
4680
}
395
396
2
uint32_t WASI::ArgsGet(WASI& wasi,
397
                       WasmMemory memory,
398
                       uint32_t argv_offset,
399
                       uint32_t argv_buf_offset) {
400
2
  Debug(wasi, "args_get(%d, %d)\n", argv_offset, argv_buf_offset);
401
402
2
  CHECK_BOUNDS_OR_RETURN(memory.size, argv_buf_offset, wasi.uvw_.argv_buf_size);
403
2
  CHECK_BOUNDS_OR_RETURN(
404
      memory.size, argv_offset, wasi.uvw_.argc * UVWASI_SERDES_SIZE_uint32_t);
405
2
  std::vector<char*> argv(wasi.uvw_.argc);
406
2
  char* argv_buf = &memory.data[argv_buf_offset];
407
2
  uvwasi_errno_t err = uvwasi_args_get(&wasi.uvw_, argv.data(), argv_buf);
408
409
2
  if (err == UVWASI_ESUCCESS) {
410
8
    for (size_t i = 0; i < wasi.uvw_.argc; i++) {
411
      uint32_t offset =
412
6
          static_cast<uint32_t>(argv_buf_offset + (argv[i] - argv[0]));
413
18
      uvwasi_serdes_write_uint32_t(
414
6
          memory.data, argv_offset + (i * UVWASI_SERDES_SIZE_uint32_t), offset);
415
    }
416
  }
417
418
2
  return err;
419
}
420
421
2
uint32_t WASI::ArgsSizesGet(WASI& wasi,
422
                            WasmMemory memory,
423
                            uint32_t argc_offset,
424
                            uint32_t argv_buf_offset) {
425
2
  Debug(wasi, "args_sizes_get(%d, %d)\n", argc_offset, argv_buf_offset);
426
2
  CHECK_BOUNDS_OR_RETURN(memory.size, argc_offset, UVWASI_SERDES_SIZE_size_t);
427
2
  CHECK_BOUNDS_OR_RETURN(
428
      memory.size, argv_buf_offset, UVWASI_SERDES_SIZE_size_t);
429
  uvwasi_size_t argc;
430
  uvwasi_size_t argv_buf_size;
431
2
  uvwasi_errno_t err = uvwasi_args_sizes_get(&wasi.uvw_, &argc, &argv_buf_size);
432
2
  if (err == UVWASI_ESUCCESS) {
433
2
    uvwasi_serdes_write_size_t(memory.data, argc_offset, argc);
434
2
    uvwasi_serdes_write_size_t(memory.data, argv_buf_offset, argv_buf_size);
435
  }
436
437
2
  return err;
438
}
439
440
8
uint32_t WASI::ClockResGet(WASI& wasi,
441
                           WasmMemory memory,
442
                           uint32_t clock_id,
443
                           uint32_t resolution_ptr) {
444
8
  Debug(wasi, "clock_res_get(%d, %d)\n", clock_id, resolution_ptr);
445
8
  CHECK_BOUNDS_OR_RETURN(
446
      memory.size, resolution_ptr, UVWASI_SERDES_SIZE_timestamp_t);
447
  uvwasi_timestamp_t resolution;
448
8
  uvwasi_errno_t err = uvwasi_clock_res_get(&wasi.uvw_, clock_id, &resolution);
449
8
  if (err == UVWASI_ESUCCESS)
450
8
    uvwasi_serdes_write_timestamp_t(memory.data, resolution_ptr, resolution);
451
452
8
  return err;
453
}
454
455
18
uint32_t WASI::ClockTimeGet(WASI& wasi,
456
                            WasmMemory memory,
457
                            uint32_t clock_id,
458
                            uint64_t precision,
459
                            uint32_t time_ptr) {
460
18
  Debug(wasi, "clock_time_get(%d, %d, %d)\n", clock_id, precision, time_ptr);
461
18
  CHECK_BOUNDS_OR_RETURN(memory.size, time_ptr, UVWASI_SERDES_SIZE_timestamp_t);
462
  uvwasi_timestamp_t time;
463
  uvwasi_errno_t err =
464
18
      uvwasi_clock_time_get(&wasi.uvw_, clock_id, precision, &time);
465
18
  if (err == UVWASI_ESUCCESS)
466
18
    uvwasi_serdes_write_timestamp_t(memory.data, time_ptr, time);
467
468
18
  return err;
469
}
470
471
4
uint32_t WASI::EnvironGet(WASI& wasi,
472
                          WasmMemory memory,
473
                          uint32_t environ_offset,
474
                          uint32_t environ_buf_offset) {
475
4
  Debug(wasi, "environ_get(%d, %d)\n", environ_offset, environ_buf_offset);
476
4
  CHECK_BOUNDS_OR_RETURN(
477
      memory.size, environ_buf_offset, wasi.uvw_.env_buf_size);
478
4
  CHECK_BOUNDS_OR_RETURN(memory.size,
479
                         environ_offset,
480
                         wasi.uvw_.envc * UVWASI_SERDES_SIZE_uint32_t);
481
4
  std::vector<char*> environment(wasi.uvw_.envc);
482
4
  char* environ_buf = &memory.data[environ_buf_offset];
483
  uvwasi_errno_t err =
484
4
      uvwasi_environ_get(&wasi.uvw_, environment.data(), environ_buf);
485
486
4
  if (err == UVWASI_ESUCCESS) {
487
316
    for (size_t i = 0; i < wasi.uvw_.envc; i++) {
488
      uint32_t offset = static_cast<uint32_t>(
489
312
          environ_buf_offset + (environment[i] - environment[0]));
490
491
936
      uvwasi_serdes_write_uint32_t(
492
312
          memory.data,
493
312
          environ_offset + (i * UVWASI_SERDES_SIZE_uint32_t),
494
          offset);
495
    }
496
  }
497
498
4
  return err;
499
}
500
501
4
uint32_t WASI::EnvironSizesGet(WASI& wasi,
502
                               WasmMemory memory,
503
                               uint32_t envc_offset,
504
                               uint32_t env_buf_offset) {
505
4
  Debug(wasi, "environ_sizes_get(%d, %d)\n", envc_offset, env_buf_offset);
506
4
  CHECK_BOUNDS_OR_RETURN(memory.size, envc_offset, UVWASI_SERDES_SIZE_size_t);
507
4
  CHECK_BOUNDS_OR_RETURN(
508
      memory.size, env_buf_offset, UVWASI_SERDES_SIZE_size_t);
509
  uvwasi_size_t envc;
510
  uvwasi_size_t env_buf_size;
511
  uvwasi_errno_t err =
512
4
      uvwasi_environ_sizes_get(&wasi.uvw_, &envc, &env_buf_size);
513
4
  if (err == UVWASI_ESUCCESS) {
514
4
    uvwasi_serdes_write_size_t(memory.data, envc_offset, envc);
515
4
    uvwasi_serdes_write_size_t(memory.data, env_buf_offset, env_buf_size);
516
  }
517
518
4
  return err;
519
}
520
521
uint32_t WASI::FdAdvise(WASI& wasi,
522
                        WasmMemory,
523
                        uint32_t fd,
524
                        uint64_t offset,
525
                        uint64_t len,
526
                        uint32_t advice) {
527
  Debug(wasi, "fd_advise(%d, %d, %d, %d)\n", fd, offset, len, advice);
528
  return uvwasi_fd_advise(&wasi.uvw_, fd, offset, len, advice);
529
}
530
531
uint32_t WASI::FdAllocate(
532
    WASI& wasi, WasmMemory, uint32_t fd, uint64_t offset, uint64_t len) {
533
  Debug(wasi, "fd_allocate(%d, %d, %d)\n", fd, offset, len);
534
  return uvwasi_fd_allocate(&wasi.uvw_, fd, offset, len);
535
}
536
537
9
uint32_t WASI::FdClose(WASI& wasi, WasmMemory, uint32_t fd) {
538
9
  Debug(wasi, "fd_close(%d)\n", fd);
539
9
  return uvwasi_fd_close(&wasi.uvw_, fd);
540
}
541
542
uint32_t WASI::FdDatasync(WASI& wasi, WasmMemory, uint32_t fd) {
543
  Debug(wasi, "fd_datasync(%d)\n", fd);
544
  return uvwasi_fd_datasync(&wasi.uvw_, fd);
545
}
546
547
45
uint32_t WASI::FdFdstatGet(WASI& wasi,
548
                           WasmMemory memory,
549
                           uint32_t fd,
550
                           uint32_t buf) {
551
45
  Debug(wasi, "fd_fdstat_get(%d, %d)\n", fd, buf);
552
45
  CHECK_BOUNDS_OR_RETURN(memory.size, buf, UVWASI_SERDES_SIZE_fdstat_t);
553
  uvwasi_fdstat_t stats;
554
45
  uvwasi_errno_t err = uvwasi_fd_fdstat_get(&wasi.uvw_, fd, &stats);
555
556
45
  if (err == UVWASI_ESUCCESS)
557
45
    uvwasi_serdes_write_fdstat_t(memory.data, buf, &stats);
558
559
45
  return err;
560
}
561
562
uint32_t WASI::FdFdstatSetFlags(WASI& wasi,
563
                                WasmMemory,
564
                                uint32_t fd,
565
                                uint32_t flags) {
566
  Debug(wasi, "fd_fdstat_set_flags(%d, %d)\n", fd, flags);
567
  return uvwasi_fd_fdstat_set_flags(&wasi.uvw_, fd, flags);
568
}
569
570
uint32_t WASI::FdFdstatSetRights(WASI& wasi,
571
                                 WasmMemory,
572
                                 uint32_t fd,
573
                                 uint64_t fs_rights_base,
574
                                 uint64_t fs_rights_inheriting) {
575
  Debug(wasi,
576
        "fd_fdstat_set_rights(%d, %d, %d)\n",
577
        fd,
578
        fs_rights_base,
579
        fs_rights_inheriting);
580
  return uvwasi_fd_fdstat_set_rights(
581
      &wasi.uvw_, fd, fs_rights_base, fs_rights_inheriting);
582
}
583
584
10
uint32_t WASI::FdFilestatGet(WASI& wasi,
585
                             WasmMemory memory,
586
                             uint32_t fd,
587
                             uint32_t buf) {
588
10
  Debug(wasi, "fd_filestat_get(%d, %d)\n", fd, buf);
589
10
  CHECK_BOUNDS_OR_RETURN(memory.size, buf, UVWASI_SERDES_SIZE_filestat_t);
590
  uvwasi_filestat_t stats;
591
10
  uvwasi_errno_t err = uvwasi_fd_filestat_get(&wasi.uvw_, fd, &stats);
592
593
10
  if (err == UVWASI_ESUCCESS)
594
10
    uvwasi_serdes_write_filestat_t(memory.data, buf, &stats);
595
596
10
  return err;
597
}
598
599
4
uint32_t WASI::FdFilestatSetSize(WASI& wasi,
600
                                 WasmMemory,
601
                                 uint32_t fd,
602
                                 uint64_t st_size) {
603
4
  Debug(wasi, "fd_filestat_set_size(%d, %d)\n", fd, st_size);
604
4
  return uvwasi_fd_filestat_set_size(&wasi.uvw_, fd, st_size);
605
}
606
607
2
uint32_t WASI::FdFilestatSetTimes(WASI& wasi,
608
                                  WasmMemory,
609
                                  uint32_t fd,
610
                                  uint64_t st_atim,
611
                                  uint64_t st_mtim,
612
                                  uint32_t fst_flags) {
613
2
  Debug(wasi,
614
        "fd_filestat_set_times(%d, %d, %d, %d)\n",
615
        fd,
616
        st_atim,
617
        st_mtim,
618
        fst_flags);
619
2
  return uvwasi_fd_filestat_set_times(
620
2
      &wasi.uvw_, fd, st_atim, st_mtim, fst_flags);
621
}
622
623
uint32_t WASI::FdPread(WASI& wasi,
624
                       WasmMemory memory,
625
                       uint32_t fd,
626
                       uint32_t iovs_ptr,
627
                       uint32_t iovs_len,
628
                       uint64_t offset,
629
                       uint32_t nread_ptr) {
630
  Debug(wasi,
631
        "uvwasi_fd_pread(%d, %d, %d, %d, %d)\n",
632
        fd,
633
        iovs_ptr,
634
        iovs_len,
635
        offset,
636
        nread_ptr);
637
  CHECK_BOUNDS_OR_RETURN(
638
      memory.size, iovs_ptr, iovs_len * UVWASI_SERDES_SIZE_iovec_t);
639
  CHECK_BOUNDS_OR_RETURN(memory.size, nread_ptr, UVWASI_SERDES_SIZE_size_t);
640
  std::vector<uvwasi_iovec_t> iovs(iovs_len);
641
  uvwasi_errno_t err;
642
643
  err = uvwasi_serdes_readv_iovec_t(
644
      memory.data, memory.size, iovs_ptr, iovs.data(), iovs_len);
645
  if (err != UVWASI_ESUCCESS) {
646
    return err;
647
  }
648
649
  uvwasi_size_t nread;
650
  err = uvwasi_fd_pread(&wasi.uvw_, fd, iovs.data(), iovs_len, offset, &nread);
651
  if (err == UVWASI_ESUCCESS)
652
    uvwasi_serdes_write_size_t(memory.data, nread_ptr, nread);
653
654
  return err;
655
}
656
657
69
uint32_t WASI::FdPrestatGet(WASI& wasi,
658
                            WasmMemory memory,
659
                            uint32_t fd,
660
                            uint32_t buf) {
661
69
  Debug(wasi, "fd_prestat_get(%d, %d)\n", fd, buf);
662
69
  CHECK_BOUNDS_OR_RETURN(memory.size, buf, UVWASI_SERDES_SIZE_prestat_t);
663
  uvwasi_prestat_t prestat;
664
69
  uvwasi_errno_t err = uvwasi_fd_prestat_get(&wasi.uvw_, fd, &prestat);
665
666
69
  if (err == UVWASI_ESUCCESS)
667
46
    uvwasi_serdes_write_prestat_t(memory.data, buf, &prestat);
668
669
69
  return err;
670
}
671
672
46
uint32_t WASI::FdPrestatDirName(WASI& wasi,
673
                                WasmMemory memory,
674
                                uint32_t fd,
675
                                uint32_t path_ptr,
676
                                uint32_t path_len) {
677
46
  Debug(wasi, "fd_prestat_dir_name(%d, %d, %d)\n", fd, path_ptr, path_len);
678
46
  CHECK_BOUNDS_OR_RETURN(memory.size, path_ptr, path_len);
679
92
  return uvwasi_fd_prestat_dir_name(
680
46
      &wasi.uvw_, fd, &memory.data[path_ptr], path_len);
681
}
682
683
uint32_t WASI::FdPwrite(WASI& wasi,
684
                        WasmMemory memory,
685
                        uint32_t fd,
686
                        uint32_t iovs_ptr,
687
                        uint32_t iovs_len,
688
                        uint64_t offset,
689
                        uint32_t nwritten_ptr) {
690
  Debug(wasi,
691
        "uvwasi_fd_pwrite(%d, %d, %d, %d, %d)\n",
692
        fd,
693
        iovs_ptr,
694
        iovs_len,
695
        offset,
696
        nwritten_ptr);
697
  CHECK_BOUNDS_OR_RETURN(
698
      memory.size, iovs_ptr, iovs_len * UVWASI_SERDES_SIZE_ciovec_t);
699
  CHECK_BOUNDS_OR_RETURN(memory.size, nwritten_ptr, UVWASI_SERDES_SIZE_size_t);
700
  std::vector<uvwasi_ciovec_t> iovs(iovs_len);
701
  uvwasi_errno_t err;
702
703
  err = uvwasi_serdes_readv_ciovec_t(
704
      memory.data, memory.size, iovs_ptr, iovs.data(), iovs_len);
705
  if (err != UVWASI_ESUCCESS) {
706
    return err;
707
  }
708
709
  uvwasi_size_t nwritten;
710
  err = uvwasi_fd_pwrite(
711
      &wasi.uvw_, fd, iovs.data(), iovs_len, offset, &nwritten);
712
  if (err == UVWASI_ESUCCESS)
713
    uvwasi_serdes_write_size_t(memory.data, nwritten_ptr, nwritten);
714
715
  return err;
716
}
717
718
25
uint32_t WASI::FdRead(WASI& wasi,
719
                      WasmMemory memory,
720
                      uint32_t fd,
721
                      uint32_t iovs_ptr,
722
                      uint32_t iovs_len,
723
                      uint32_t nread_ptr) {
724
25
  Debug(wasi, "fd_read(%d, %d, %d, %d)\n", fd, iovs_ptr, iovs_len, nread_ptr);
725
25
  CHECK_BOUNDS_OR_RETURN(
726
      memory.size, iovs_ptr, iovs_len * UVWASI_SERDES_SIZE_iovec_t);
727
25
  CHECK_BOUNDS_OR_RETURN(memory.size, nread_ptr, UVWASI_SERDES_SIZE_size_t);
728
50
  std::vector<uvwasi_iovec_t> iovs(iovs_len);
729
  uvwasi_errno_t err;
730
731
25
  err = uvwasi_serdes_readv_iovec_t(
732
25
      memory.data, memory.size, iovs_ptr, iovs.data(), iovs_len);
733
25
  if (err != UVWASI_ESUCCESS) {
734
    return err;
735
  }
736
737
  uvwasi_size_t nread;
738
25
  err = uvwasi_fd_read(&wasi.uvw_, fd, iovs.data(), iovs_len, &nread);
739
25
  if (err == UVWASI_ESUCCESS)
740
25
    uvwasi_serdes_write_size_t(memory.data, nread_ptr, nread);
741
742
25
  return err;
743
}
744
745
2
uint32_t WASI::FdReaddir(WASI& wasi,
746
                         WasmMemory memory,
747
                         uint32_t fd,
748
                         uint32_t buf_ptr,
749
                         uint32_t buf_len,
750
                         uint64_t cookie,
751
                         uint32_t bufused_ptr) {
752
2
  Debug(wasi,
753
        "uvwasi_fd_readdir(%d, %d, %d, %d, %d)\n",
754
        fd,
755
        buf_ptr,
756
        buf_len,
757
        cookie,
758
        bufused_ptr);
759
2
  CHECK_BOUNDS_OR_RETURN(memory.size, buf_ptr, buf_len);
760
2
  CHECK_BOUNDS_OR_RETURN(memory.size, bufused_ptr, UVWASI_SERDES_SIZE_size_t);
761
  uvwasi_size_t bufused;
762
6
  uvwasi_errno_t err = uvwasi_fd_readdir(
763
2
      &wasi.uvw_, fd, &memory.data[buf_ptr], buf_len, cookie, &bufused);
764
2
  if (err == UVWASI_ESUCCESS)
765
2
    uvwasi_serdes_write_size_t(memory.data, bufused_ptr, bufused);
766
767
2
  return err;
768
}
769
770
2
uint32_t WASI::FdRenumber(WASI& wasi, WasmMemory, uint32_t from, uint32_t to) {
771
2
  Debug(wasi, "fd_renumber(%d, %d)\n", from, to);
772
2
  return uvwasi_fd_renumber(&wasi.uvw_, from, to);
773
}
774
775
3
uint32_t WASI::FdSeek(WASI& wasi,
776
                      WasmMemory memory,
777
                      uint32_t fd,
778
                      int64_t offset,
779
                      uint32_t whence,
780
                      uint32_t newoffset_ptr) {
781
3
  Debug(wasi, "fd_seek(%d, %d, %d, %d)\n", fd, offset, whence, newoffset_ptr);
782
3
  CHECK_BOUNDS_OR_RETURN(
783
      memory.size, newoffset_ptr, UVWASI_SERDES_SIZE_filesize_t);
784
  uvwasi_filesize_t newoffset;
785
  uvwasi_errno_t err =
786
3
      uvwasi_fd_seek(&wasi.uvw_, fd, offset, whence, &newoffset);
787
3
  if (err == UVWASI_ESUCCESS)
788
3
    uvwasi_serdes_write_filesize_t(memory.data, newoffset_ptr, newoffset);
789
790
3
  return err;
791
}
792
793
uint32_t WASI::FdSync(WASI& wasi, WasmMemory, uint32_t fd) {
794
  Debug(wasi, "fd_sync(%d)\n", fd);
795
  return uvwasi_fd_sync(&wasi.uvw_, fd);
796
}
797
798
6
uint32_t WASI::FdTell(WASI& wasi,
799
                      WasmMemory memory,
800
                      uint32_t fd,
801
                      uint32_t offset_ptr) {
802
6
  Debug(wasi, "fd_tell(%d, %d)\n", fd, offset_ptr);
803
6
  CHECK_BOUNDS_OR_RETURN(
804
      memory.size, offset_ptr, UVWASI_SERDES_SIZE_filesize_t);
805
  uvwasi_filesize_t offset;
806
6
  uvwasi_errno_t err = uvwasi_fd_tell(&wasi.uvw_, fd, &offset);
807
808
6
  if (err == UVWASI_ESUCCESS)
809
6
    uvwasi_serdes_write_filesize_t(memory.data, offset_ptr, offset);
810
811
6
  return err;
812
}
813
814
17
uint32_t WASI::FdWrite(WASI& wasi,
815
                       WasmMemory memory,
816
                       uint32_t fd,
817
                       uint32_t iovs_ptr,
818
                       uint32_t iovs_len,
819
                       uint32_t nwritten_ptr) {
820
17
  Debug(wasi,
821
        "fd_write(%d, %d, %d, %d)\n",
822
        fd,
823
        iovs_ptr,
824
        iovs_len,
825
        nwritten_ptr);
826
17
  CHECK_BOUNDS_OR_RETURN(
827
      memory.size, iovs_ptr, iovs_len * UVWASI_SERDES_SIZE_ciovec_t);
828
17
  CHECK_BOUNDS_OR_RETURN(memory.size, nwritten_ptr, UVWASI_SERDES_SIZE_size_t);
829
34
  std::vector<uvwasi_ciovec_t> iovs(iovs_len);
830
  uvwasi_errno_t err;
831
832
17
  err = uvwasi_serdes_readv_ciovec_t(
833
17
      memory.data, memory.size, iovs_ptr, iovs.data(), iovs_len);
834
17
  if (err != UVWASI_ESUCCESS) {
835
    return err;
836
  }
837
838
  uvwasi_size_t nwritten;
839
17
  err = uvwasi_fd_write(&wasi.uvw_, fd, iovs.data(), iovs_len, &nwritten);
840
17
  if (err == UVWASI_ESUCCESS)
841
17
    uvwasi_serdes_write_size_t(memory.data, nwritten_ptr, nwritten);
842
843
17
  return err;
844
}
845
846
4
uint32_t WASI::PathCreateDirectory(WASI& wasi,
847
                                   WasmMemory memory,
848
                                   uint32_t fd,
849
                                   uint32_t path_ptr,
850
                                   uint32_t path_len) {
851
4
  Debug(wasi, "path_create_directory(%d, %d, %d)\n", fd, path_ptr, path_len);
852
4
  CHECK_BOUNDS_OR_RETURN(memory.size, path_ptr, path_len);
853
12
  uvwasi_errno_t err = uvwasi_path_create_directory(
854
4
      &wasi.uvw_, fd, &memory.data[path_ptr], path_len);
855
4
  return err;
856
}
857
858
12
uint32_t WASI::PathFilestatGet(WASI& wasi,
859
                               WasmMemory memory,
860
                               uint32_t fd,
861
                               uint32_t flags,
862
                               uint32_t path_ptr,
863
                               uint32_t path_len,
864
                               uint32_t buf_ptr) {
865
12
  Debug(wasi,
866
        "path_filestat_get(%d, %d, %d)\n",
867
        fd,
868
        path_ptr,
869
        path_len);
870
12
  CHECK_BOUNDS_OR_RETURN(memory.size, path_ptr, path_len);
871
12
  CHECK_BOUNDS_OR_RETURN(memory.size, buf_ptr, UVWASI_SERDES_SIZE_filestat_t);
872
  uvwasi_filestat_t stats;
873
36
  uvwasi_errno_t err = uvwasi_path_filestat_get(
874
12
      &wasi.uvw_, fd, flags, &memory.data[path_ptr], path_len, &stats);
875
12
  if (err == UVWASI_ESUCCESS)
876
8
    uvwasi_serdes_write_filestat_t(memory.data, buf_ptr, &stats);
877
878
12
  return err;
879
}
880
881
uint32_t WASI::PathFilestatSetTimes(WASI& wasi,
882
                                    WasmMemory memory,
883
                                    uint32_t fd,
884
                                    uint32_t flags,
885
                                    uint32_t path_ptr,
886
                                    uint32_t path_len,
887
                                    uint64_t st_atim,
888
                                    uint64_t st_mtim,
889
                                    uint32_t fst_flags) {
890
  Debug(wasi,
891
        "path_filestat_set_times(%d, %d, %d, %d, %d, %d, %d)\n",
892
        fd,
893
        flags,
894
        path_ptr,
895
        path_len,
896
        st_atim,
897
        st_mtim,
898
        fst_flags);
899
  CHECK_BOUNDS_OR_RETURN(memory.size, path_ptr, path_len);
900
  return uvwasi_path_filestat_set_times(&wasi.uvw_,
901
                                        fd,
902
                                        flags,
903
                                        &memory.data[path_ptr],
904
                                        path_len,
905
                                        st_atim,
906
                                        st_mtim,
907
                                        fst_flags);
908
}
909
910
1
uint32_t WASI::PathLink(WASI& wasi,
911
                        WasmMemory memory,
912
                        uint32_t old_fd,
913
                        uint32_t old_flags,
914
                        uint32_t old_path_ptr,
915
                        uint32_t old_path_len,
916
                        uint32_t new_fd,
917
                        uint32_t new_path_ptr,
918
                        uint32_t new_path_len) {
919
1
  Debug(wasi,
920
        "path_link(%d, %d, %d, %d, %d, %d, %d)\n",
921
        old_fd,
922
        old_flags,
923
        old_path_ptr,
924
        old_path_len,
925
        new_fd,
926
        new_path_ptr,
927
        new_path_len);
928
1
  CHECK_BOUNDS_OR_RETURN(memory.size, old_path_ptr, old_path_len);
929
1
  CHECK_BOUNDS_OR_RETURN(memory.size, new_path_ptr, new_path_len);
930
5
  return uvwasi_path_link(&wasi.uvw_,
931
                          old_fd,
932
                          old_flags,
933
2
                          &memory.data[old_path_ptr],
934
                          old_path_len,
935
                          new_fd,
936
1
                          &memory.data[new_path_ptr],
937
1
                          new_path_len);
938
}
939
940
26
uint32_t WASI::PathOpen(WASI& wasi,
941
                        WasmMemory memory,
942
                        uint32_t dirfd,
943
                        uint32_t dirflags,
944
                        uint32_t path_ptr,
945
                        uint32_t path_len,
946
                        uint32_t o_flags,
947
                        uint64_t fs_rights_base,
948
                        uint64_t fs_rights_inheriting,
949
                        uint32_t fs_flags,
950
                        uint32_t fd_ptr) {
951
26
  Debug(wasi,
952
        "path_open(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n",
953
        dirfd,
954
        dirflags,
955
        path_ptr,
956
        path_len,
957
        o_flags,
958
        fs_rights_base,
959
        fs_rights_inheriting,
960
        fs_flags,
961
        fd_ptr);
962
26
  CHECK_BOUNDS_OR_RETURN(memory.size, path_ptr, path_len);
963
26
  CHECK_BOUNDS_OR_RETURN(memory.size, fd_ptr, UVWASI_SERDES_SIZE_fd_t);
964
  uvwasi_fd_t fd;
965
78
  uvwasi_errno_t err = uvwasi_path_open(&wasi.uvw_,
966
                                        dirfd,
967
                                        dirflags,
968
26
                                        &memory.data[path_ptr],
969
                                        path_len,
970
                                        static_cast<uvwasi_oflags_t>(o_flags),
971
                                        fs_rights_base,
972
                                        fs_rights_inheriting,
973
                                        static_cast<uvwasi_fdflags_t>(fs_flags),
974
                                        &fd);
975
26
  if (err == UVWASI_ESUCCESS)
976
20
    uvwasi_serdes_write_size_t(memory.data, fd_ptr, fd);
977
978
26
  return err;
979
}
980
981
1
uint32_t WASI::PathReadlink(WASI& wasi,
982
                            WasmMemory memory,
983
                            uint32_t fd,
984
                            uint32_t path_ptr,
985
                            uint32_t path_len,
986
                            uint32_t buf_ptr,
987
                            uint32_t buf_len,
988
                            uint32_t bufused_ptr) {
989
1
  Debug(wasi,
990
        "path_readlink(%d, %d, %d, %d, %d, %d)\n",
991
        fd,
992
        path_ptr,
993
        path_len,
994
        buf_ptr,
995
        buf_len,
996
        bufused_ptr);
997
1
  CHECK_BOUNDS_OR_RETURN(memory.size, path_ptr, path_len);
998
1
  CHECK_BOUNDS_OR_RETURN(memory.size, buf_ptr, buf_len);
999
1
  CHECK_BOUNDS_OR_RETURN(memory.size, bufused_ptr, UVWASI_SERDES_SIZE_size_t);
1000
  uvwasi_size_t bufused;
1001
4
  uvwasi_errno_t err = uvwasi_path_readlink(&wasi.uvw_,
1002
                                            fd,
1003
2
                                            &memory.data[path_ptr],
1004
                                            path_len,
1005
1
                                            &memory.data[buf_ptr],
1006
                                            buf_len,
1007
                                            &bufused);
1008
1
  if (err == UVWASI_ESUCCESS)
1009
1
    uvwasi_serdes_write_size_t(memory.data, bufused_ptr, bufused);
1010
1011
1
  return err;
1012
}
1013
1014
2
uint32_t WASI::PathRemoveDirectory(WASI& wasi,
1015
                                   WasmMemory memory,
1016
                                   uint32_t fd,
1017
                                   uint32_t path_ptr,
1018
                                   uint32_t path_len) {
1019
2
  Debug(wasi, "path_remove_directory(%d, %d, %d)\n", fd, path_ptr, path_len);
1020
2
  CHECK_BOUNDS_OR_RETURN(memory.size, path_ptr, path_len);
1021
6
  return uvwasi_path_remove_directory(
1022
2
      &wasi.uvw_, fd, &memory.data[path_ptr], path_len);
1023
}
1024
1025
uint32_t WASI::PathRename(WASI& wasi,
1026
                          WasmMemory memory,
1027
                          uint32_t old_fd,
1028
                          uint32_t old_path_ptr,
1029
                          uint32_t old_path_len,
1030
                          uint32_t new_fd,
1031
                          uint32_t new_path_ptr,
1032
                          uint32_t new_path_len) {
1033
  Debug(wasi,
1034
        "path_rename(%d, %d, %d, %d, %d, %d)\n",
1035
        old_fd,
1036
        old_path_ptr,
1037
        old_path_len,
1038
        new_fd,
1039
        new_path_ptr,
1040
        new_path_len);
1041
  CHECK_BOUNDS_OR_RETURN(memory.size, old_path_ptr, old_path_len);
1042
  CHECK_BOUNDS_OR_RETURN(memory.size, new_path_ptr, new_path_len);
1043
  return uvwasi_path_rename(&wasi.uvw_,
1044
                            old_fd,
1045
                            &memory.data[old_path_ptr],
1046
                            old_path_len,
1047
                            new_fd,
1048
                            &memory.data[new_path_ptr],
1049
                            new_path_len);
1050
}
1051
1052
1
uint32_t WASI::PathSymlink(WASI& wasi,
1053
                           WasmMemory memory,
1054
                           uint32_t old_path_ptr,
1055
                           uint32_t old_path_len,
1056
                           uint32_t fd,
1057
                           uint32_t new_path_ptr,
1058
                           uint32_t new_path_len) {
1059
1
  Debug(wasi,
1060
        "path_symlink(%d, %d, %d, %d, %d)\n",
1061
        old_path_ptr,
1062
        old_path_len,
1063
        fd,
1064
        new_path_ptr,
1065
        new_path_len);
1066
1
  CHECK_BOUNDS_OR_RETURN(memory.size, old_path_ptr, old_path_len);
1067
1
  CHECK_BOUNDS_OR_RETURN(memory.size, new_path_ptr, new_path_len);
1068
5
  return uvwasi_path_symlink(&wasi.uvw_,
1069
2
                             &memory.data[old_path_ptr],
1070
                             old_path_len,
1071
                             fd,
1072
1
                             &memory.data[new_path_ptr],
1073
1
                             new_path_len);
1074
}
1075
1076
2
uint32_t WASI::PathUnlinkFile(WASI& wasi,
1077
                              WasmMemory memory,
1078
                              uint32_t fd,
1079
                              uint32_t path_ptr,
1080
                              uint32_t path_len) {
1081
2
  Debug(wasi, "path_unlink_file(%d, %d, %d)\n", fd, path_ptr, path_len);
1082
2
  CHECK_BOUNDS_OR_RETURN(memory.size, path_ptr, path_len);
1083
6
  return uvwasi_path_unlink_file(
1084
2
      &wasi.uvw_, fd, &memory.data[path_ptr], path_len);
1085
}
1086
1087
10
uint32_t WASI::PollOneoff(WASI& wasi,
1088
                          WasmMemory memory,
1089
                          uint32_t in_ptr,
1090
                          uint32_t out_ptr,
1091
                          uint32_t nsubscriptions,
1092
                          uint32_t nevents_ptr) {
1093
10
  Debug(wasi,
1094
        "poll_oneoff(%d, %d, %d, %d)\n",
1095
        in_ptr,
1096
        out_ptr,
1097
        nsubscriptions,
1098
        nevents_ptr);
1099
10
  CHECK_BOUNDS_OR_RETURN(
1100
      memory.size, in_ptr, nsubscriptions * UVWASI_SERDES_SIZE_subscription_t);
1101
10
  CHECK_BOUNDS_OR_RETURN(
1102
      memory.size, out_ptr, nsubscriptions * UVWASI_SERDES_SIZE_event_t);
1103
10
  CHECK_BOUNDS_OR_RETURN(memory.size, nevents_ptr, UVWASI_SERDES_SIZE_size_t);
1104
20
  std::vector<uvwasi_subscription_t> in(nsubscriptions);
1105
10
  std::vector<uvwasi_event_t> out(nsubscriptions);
1106
1107
26
  for (uint32_t i = 0; i < nsubscriptions; ++i) {
1108
16
    uvwasi_serdes_read_subscription_t(memory.data, in_ptr, &in[i]);
1109
16
    in_ptr += UVWASI_SERDES_SIZE_subscription_t;
1110
  }
1111
1112
  uvwasi_size_t nevents;
1113
20
  uvwasi_errno_t err = uvwasi_poll_oneoff(
1114
10
      &wasi.uvw_, in.data(), out.data(), nsubscriptions, &nevents);
1115
10
  if (err == UVWASI_ESUCCESS) {
1116
10
    uvwasi_serdes_write_size_t(memory.data, nevents_ptr, nevents);
1117
1118
26
    for (uint32_t i = 0; i < nsubscriptions; ++i) {
1119
16
      uvwasi_serdes_write_event_t(memory.data, out_ptr, &out[i]);
1120
16
      out_ptr += UVWASI_SERDES_SIZE_event_t;
1121
    }
1122
  }
1123
1124
10
  return err;
1125
}
1126
1127
2
void WASI::ProcExit(WASI& wasi, WasmMemory, uint32_t code) {
1128
2
  Debug(wasi, "proc_exit(%d)\n", code);
1129
2
  uvwasi_proc_exit(&wasi.uvw_, code);
1130
}
1131
1132
uint32_t WASI::ProcRaise(WASI& wasi, WasmMemory, uint32_t sig) {
1133
  Debug(wasi, "proc_raise(%d)\n", sig);
1134
  return uvwasi_proc_raise(&wasi.uvw_, sig);
1135
}
1136
1137
2
uint32_t WASI::RandomGet(WASI& wasi,
1138
                         WasmMemory memory,
1139
                         uint32_t buf_ptr,
1140
                         uint32_t buf_len) {
1141
2
  Debug(wasi, "random_get(%d, %d)\n", buf_ptr, buf_len);
1142
2
  CHECK_BOUNDS_OR_RETURN(memory.size, buf_ptr, buf_len);
1143
2
  return uvwasi_random_get(&wasi.uvw_, &memory.data[buf_ptr], buf_len);
1144
}
1145
1146
uint32_t WASI::SchedYield(WASI& wasi, WasmMemory) {
1147
  Debug(wasi, "sched_yield()\n");
1148
  return uvwasi_sched_yield(&wasi.uvw_);
1149
}
1150
1151
uint32_t WASI::SockRecv(WASI& wasi,
1152
                        WasmMemory memory,
1153
                        uint32_t sock,
1154
                        uint32_t ri_data_ptr,
1155
                        uint32_t ri_data_len,
1156
                        uint32_t ri_flags,
1157
                        uint32_t ro_datalen_ptr,
1158
                        uint32_t ro_flags_ptr) {
1159
  Debug(wasi,
1160
        "sock_recv(%d, %d, %d, %d, %d, %d)\n",
1161
        sock,
1162
        ri_data_ptr,
1163
        ri_data_len,
1164
        ri_flags,
1165
        ro_datalen_ptr,
1166
        ro_flags_ptr);
1167
  CHECK_BOUNDS_OR_RETURN(
1168
      memory.size, ri_data_ptr, ri_data_len * UVWASI_SERDES_SIZE_iovec_t);
1169
  CHECK_BOUNDS_OR_RETURN(memory.size, ro_datalen_ptr, 4);
1170
  CHECK_BOUNDS_OR_RETURN(memory.size, ro_flags_ptr, 4);
1171
  std::vector<uvwasi_iovec_t> ri_data(ri_data_len);
1172
  uvwasi_errno_t err = uvwasi_serdes_readv_iovec_t(
1173
      memory.data, memory.size, ri_data_ptr, ri_data.data(), ri_data_len);
1174
  if (err != UVWASI_ESUCCESS) {
1175
    return err;
1176
  }
1177
1178
  uvwasi_size_t ro_datalen;
1179
  uvwasi_roflags_t ro_flags;
1180
  err = uvwasi_sock_recv(&wasi.uvw_,
1181
                         sock,
1182
                         ri_data.data(),
1183
                         ri_data_len,
1184
                         ri_flags,
1185
                         &ro_datalen,
1186
                         &ro_flags);
1187
  if (err == UVWASI_ESUCCESS) {
1188
    uvwasi_serdes_write_size_t(memory.data, ro_datalen_ptr, ro_datalen);
1189
    uvwasi_serdes_write_roflags_t(memory.data, ro_flags_ptr, ro_flags);
1190
  }
1191
1192
  return err;
1193
}
1194
1195
uint32_t WASI::SockSend(WASI& wasi,
1196
                        WasmMemory memory,
1197
                        uint32_t sock,
1198
                        uint32_t si_data_ptr,
1199
                        uint32_t si_data_len,
1200
                        uint32_t si_flags,
1201
                        uint32_t so_datalen_ptr) {
1202
  Debug(wasi,
1203
        "sock_send(%d, %d, %d, %d, %d)\n",
1204
        sock,
1205
        si_data_ptr,
1206
        si_data_len,
1207
        si_flags,
1208
        so_datalen_ptr);
1209
  CHECK_BOUNDS_OR_RETURN(
1210
      memory.size, si_data_ptr, si_data_len * UVWASI_SERDES_SIZE_ciovec_t);
1211
  CHECK_BOUNDS_OR_RETURN(
1212
      memory.size, so_datalen_ptr, UVWASI_SERDES_SIZE_size_t);
1213
  std::vector<uvwasi_ciovec_t> si_data(si_data_len);
1214
  uvwasi_errno_t err = uvwasi_serdes_readv_ciovec_t(
1215
      memory.data, memory.size, si_data_ptr, si_data.data(), si_data_len);
1216
  if (err != UVWASI_ESUCCESS) {
1217
    return err;
1218
  }
1219
1220
  uvwasi_size_t so_datalen;
1221
  err = uvwasi_sock_send(
1222
      &wasi.uvw_, sock, si_data.data(), si_data_len, si_flags, &so_datalen);
1223
  if (err == UVWASI_ESUCCESS)
1224
    uvwasi_serdes_write_size_t(memory.data, so_datalen_ptr, so_datalen);
1225
1226
  return err;
1227
}
1228
1229
uint32_t WASI::SockShutdown(WASI& wasi,
1230
                            WasmMemory,
1231
                            uint32_t sock,
1232
                            uint32_t how) {
1233
  Debug(wasi, "sock_shutdown(%d, %d)\n", sock, how);
1234
  return uvwasi_sock_shutdown(&wasi.uvw_, sock, how);
1235
}
1236
1237
57
void WASI::_SetMemory(const FunctionCallbackInfo<Value>& args) {
1238
  WASI* wasi;
1239
59
  ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This());
1240
57
  CHECK_EQ(args.Length(), 1);
1241
57
  if (!args[0]->IsWasmMemoryObject()) {
1242
2
    return node::THROW_ERR_INVALID_ARG_TYPE(
1243
        wasi->env(),
1244
        "\"instance.exports.memory\" property must be a WebAssembly.Memory "
1245
2
        "object");
1246
  }
1247
220
  wasi->memory_.Reset(wasi->env()->isolate(), args[0].As<WasmMemoryObject>());
1248
}
1249
1250
52
static void Initialize(Local<Object> target,
1251
                       Local<Value> unused,
1252
                       Local<Context> context,
1253
                       void* priv) {
1254
52
  Environment* env = Environment::GetCurrent(context);
1255
52
  Isolate* isolate = env->isolate();
1256
1257
52
  Local<FunctionTemplate> tmpl = NewFunctionTemplate(isolate, WASI::New);
1258
104
  tmpl->InstanceTemplate()->SetInternalFieldCount(WASI::kInternalFieldCount);
1259
52
  tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
1260
1261
#define V(F, name)                                                             \
1262
  SetFunction<decltype(&WASI::F), WASI::F>(WASI::F, env, name, tmpl);
1263
1264
52
  V(ArgsGet, "args_get")
1265
52
  V(ArgsSizesGet, "args_sizes_get")
1266
52
  V(ClockResGet, "clock_res_get")
1267
52
  V(ClockTimeGet, "clock_time_get")
1268
52
  V(EnvironGet, "environ_get")
1269
52
  V(EnvironSizesGet, "environ_sizes_get")
1270
52
  V(FdAdvise, "fd_advise")
1271
52
  V(FdAllocate, "fd_allocate")
1272
52
  V(FdClose, "fd_close")
1273
52
  V(FdDatasync, "fd_datasync")
1274
52
  V(FdFdstatGet, "fd_fdstat_get")
1275
52
  V(FdFdstatSetFlags, "fd_fdstat_set_flags")
1276
52
  V(FdFdstatSetRights, "fd_fdstat_set_rights")
1277
52
  V(FdFilestatGet, "fd_filestat_get")
1278
52
  V(FdFilestatSetSize, "fd_filestat_set_size")
1279
52
  V(FdFilestatSetTimes, "fd_filestat_set_times")
1280
52
  V(FdPread, "fd_pread")
1281
52
  V(FdPrestatGet, "fd_prestat_get")
1282
52
  V(FdPrestatDirName, "fd_prestat_dir_name")
1283
52
  V(FdPwrite, "fd_pwrite")
1284
52
  V(FdRead, "fd_read")
1285
52
  V(FdReaddir, "fd_readdir")
1286
52
  V(FdRenumber, "fd_renumber")
1287
52
  V(FdSeek, "fd_seek")
1288
52
  V(FdSync, "fd_sync")
1289
52
  V(FdTell, "fd_tell")
1290
52
  V(FdWrite, "fd_write")
1291
52
  V(PathCreateDirectory, "path_create_directory")
1292
52
  V(PathFilestatGet, "path_filestat_get")
1293
52
  V(PathFilestatSetTimes, "path_filestat_set_times")
1294
52
  V(PathLink, "path_link")
1295
52
  V(PathOpen, "path_open")
1296
52
  V(PathReadlink, "path_readlink")
1297
52
  V(PathRemoveDirectory, "path_remove_directory")
1298
52
  V(PathRename, "path_rename")
1299
52
  V(PathSymlink, "path_symlink")
1300
52
  V(PathUnlinkFile, "path_unlink_file")
1301
52
  V(PollOneoff, "poll_oneoff")
1302
52
  V(ProcExit, "proc_exit")
1303
52
  V(ProcRaise, "proc_raise")
1304
52
  V(RandomGet, "random_get")
1305
52
  V(SchedYield, "sched_yield")
1306
52
  V(SockRecv, "sock_recv")
1307
52
  V(SockSend, "sock_send")
1308
52
  V(SockShutdown, "sock_shutdown")
1309
#undef V
1310
1311
52
  SetInstanceMethod(isolate, tmpl, "_setMemory", WASI::_SetMemory);
1312
1313
52
  SetConstructorFunction(context, target, "WASI", tmpl);
1314
52
}
1315
1316
1317
}  // namespace wasi
1318
}  // namespace node
1319
1320
5789
NODE_BINDING_CONTEXT_AWARE_INTERNAL(wasi, node::wasi::Initialize)