@tybys/wasm-util 0.8.3 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -121,6 +121,7 @@ async function resolvePathAsync(fs, fileDescriptor, path, flags) {
121
121
  const encoder = /*#__PURE__*/ new TextEncoder();
122
122
  // eslint-disable-next-line spaced-comment
123
123
  const decoder = /*#__PURE__*/ new TextDecoder();
124
+ const INT64_MAX = (BigInt(1) << BigInt(63)) - BigInt(1);
124
125
  function readStdin() {
125
126
  const value = window.prompt();
126
127
  if (value === null)
@@ -128,6 +129,14 @@ function readStdin() {
128
129
  const buffer = new TextEncoder().encode(value + '\n');
129
130
  return buffer;
130
131
  }
132
+ function validateFstFlagsOrReturn(flags) {
133
+ return (Boolean((flags) & ~(types_1.WasiFstFlag.SET_ATIM | types_1.WasiFstFlag.SET_ATIM_NOW |
134
+ types_1.WasiFstFlag.SET_MTIM | types_1.WasiFstFlag.SET_MTIM_NOW)) ||
135
+ ((flags) & (types_1.WasiFstFlag.SET_ATIM | types_1.WasiFstFlag.SET_ATIM_NOW)) ===
136
+ (types_1.WasiFstFlag.SET_ATIM | types_1.WasiFstFlag.SET_ATIM_NOW) ||
137
+ ((flags) & (types_1.WasiFstFlag.SET_MTIM | types_1.WasiFstFlag.SET_MTIM_NOW)) ===
138
+ (types_1.WasiFstFlag.SET_MTIM | types_1.WasiFstFlag.SET_MTIM_NOW));
139
+ }
131
140
  class WASI {
132
141
  constructor(args, env, fds, asyncFs, fs, asyncify) {
133
142
  this.args_get = syscallWrap(this, 'args_get', function (argv, argv_buf) {
@@ -224,7 +233,7 @@ class WASI {
224
233
  case types_1.WasiClockid.MONOTONIC:
225
234
  case types_1.WasiClockid.PROCESS_CPUTIME_ID:
226
235
  case types_1.WasiClockid.THREAD_CPUTIME_ID: {
227
- const t = performance.now();
236
+ const t = performance.now() / 1000;
228
237
  const s = Math.trunc(t);
229
238
  const ms = Math.floor((t - s) * 1000);
230
239
  const result = BigInt(s) * BigInt(1000000000) + BigInt(ms) * BigInt(1000000);
@@ -288,7 +297,7 @@ class WASI {
288
297
  const { view } = getMemory(this);
289
298
  // preopen type is dir(0)
290
299
  view.setUint32(prestat, 0, true);
291
- view.setUint32(prestat + 4, encoder.encode(fileDescriptor.path).length + 1, true);
300
+ view.setUint32(prestat + 4, encoder.encode(fileDescriptor.path).length, true);
292
301
  return types_1.WasiErrno.ESUCCESS;
293
302
  });
294
303
  this.fd_prestat_dir_name = syscallWrap(this, 'fd_prestat_dir_name', function (fd, path, path_len) {
@@ -301,7 +310,7 @@ class WASI {
301
310
  const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
302
311
  if (fileDescriptor.preopen !== 1)
303
312
  return types_1.WasiErrno.EBADF;
304
- const buffer = encoder.encode(fileDescriptor.path + '\0');
313
+ const buffer = encoder.encode(fileDescriptor.path);
305
314
  const size = buffer.length;
306
315
  if (size > path_len)
307
316
  return types_1.WasiErrno.ENOBUFS;
@@ -496,6 +505,9 @@ class WASI {
496
505
  this.sock_shutdown = syscallWrap(this, 'sock_shutdown', function () {
497
506
  return types_1.WasiErrno.ENOTSUP;
498
507
  });
508
+ this.sock_accept = syscallWrap(this, 'sock_accept', function () {
509
+ return types_1.WasiErrno.ENOTSUP;
510
+ });
499
511
  _wasi.set(this, {
500
512
  fds,
501
513
  args,
@@ -611,11 +623,17 @@ class WASI {
611
623
  return { fileDescriptor, atim, mtim };
612
624
  }
613
625
  defineImport('fd_filestat_set_times', function fd_filestat_set_times(fd, atim, mtim, flags) {
626
+ if (validateFstFlagsOrReturn(flags)) {
627
+ return types_1.WasiErrno.EINVAL;
628
+ }
614
629
  const { fileDescriptor, atim: atimRes, mtim: mtimRes } = fdFilestatGetTimes.call(this, fd, atim, mtim, flags);
615
630
  const fs = getFs(this);
616
631
  fs.futimesSync(fileDescriptor.fd, Number(atimRes), Number(mtimRes));
617
632
  return types_1.WasiErrno.ESUCCESS;
618
633
  }, async function fd_filestat_set_times(fd, atim, mtim, flags) {
634
+ if (validateFstFlagsOrReturn(flags)) {
635
+ return types_1.WasiErrno.EINVAL;
636
+ }
619
637
  const { fileDescriptor, atim: atimRes, mtim: mtimRes } = fdFilestatGetTimes.call(this, fd, atim, mtim, flags);
620
638
  const h = fileDescriptor.fd;
621
639
  await h.utimes(Number(atimRes), Number(mtimRes));
@@ -624,12 +642,16 @@ class WASI {
624
642
  defineImport('fd_pread', function fd_pread(fd, iovs, iovslen, offset, size) {
625
643
  iovs = Number(iovs);
626
644
  size = Number(size);
627
- if (iovs === 0 || size === 0) {
645
+ if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
628
646
  return types_1.WasiErrno.EINVAL;
629
647
  }
630
648
  const { HEAPU8, view } = getMemory(this);
631
649
  const wasi = _wasi.get(this);
632
650
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ | types_1.WasiRights.FD_SEEK, BigInt(0));
651
+ if (!iovslen) {
652
+ view.setUint32(size, 0, true);
653
+ return types_1.WasiErrno.ESUCCESS;
654
+ }
633
655
  let totalSize = 0;
634
656
  const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
635
657
  const offset = iovs + (i * 8);
@@ -656,12 +678,16 @@ class WASI {
656
678
  }, async function (fd, iovs, iovslen, offset, size) {
657
679
  iovs = Number(iovs);
658
680
  size = Number(size);
659
- if (iovs === 0 || size === 0) {
681
+ if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
660
682
  return types_1.WasiErrno.EINVAL;
661
683
  }
662
684
  const { HEAPU8, view } = getMemory(this);
663
685
  const wasi = _wasi.get(this);
664
686
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ | types_1.WasiRights.FD_SEEK, BigInt(0));
687
+ if (!iovslen) {
688
+ view.setUint32(size, 0, true);
689
+ return types_1.WasiErrno.ESUCCESS;
690
+ }
665
691
  let totalSize = 0;
666
692
  const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
667
693
  const offset = iovs + (i * 8);
@@ -681,12 +707,16 @@ class WASI {
681
707
  defineImport('fd_pwrite', function fd_pwrite(fd, iovs, iovslen, offset, size) {
682
708
  iovs = Number(iovs);
683
709
  size = Number(size);
684
- if (iovs === 0 || size === 0) {
710
+ if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
685
711
  return types_1.WasiErrno.EINVAL;
686
712
  }
687
713
  const { HEAPU8, view } = getMemory(this);
688
714
  const wasi = _wasi.get(this);
689
715
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE | types_1.WasiRights.FD_SEEK, BigInt(0));
716
+ if (!iovslen) {
717
+ view.setUint32(size, 0, true);
718
+ return types_1.WasiErrno.ESUCCESS;
719
+ }
690
720
  const buffer = (0, fd_1.concatBuffer)(Array.from({ length: Number(iovslen) }, (_, i) => {
691
721
  const offset = iovs + (i * 8);
692
722
  const buf = view.getInt32(offset, true);
@@ -700,12 +730,16 @@ class WASI {
700
730
  }, async function fd_pwrite(fd, iovs, iovslen, offset, size) {
701
731
  iovs = Number(iovs);
702
732
  size = Number(size);
703
- if (iovs === 0 || size === 0) {
733
+ if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
704
734
  return types_1.WasiErrno.EINVAL;
705
735
  }
706
736
  const { HEAPU8, view } = getMemory(this);
707
737
  const wasi = _wasi.get(this);
708
738
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE | types_1.WasiRights.FD_SEEK, BigInt(0));
739
+ if (!iovslen) {
740
+ view.setUint32(size, 0, true);
741
+ return types_1.WasiErrno.ESUCCESS;
742
+ }
709
743
  const buffer = (0, fd_1.concatBuffer)(Array.from({ length: Number(iovslen) }, (_, i) => {
710
744
  const offset = iovs + (i * 8);
711
745
  const buf = view.getInt32(offset, true);
@@ -719,12 +753,16 @@ class WASI {
719
753
  defineImport('fd_read', function fd_read(fd, iovs, iovslen, size) {
720
754
  iovs = Number(iovs);
721
755
  size = Number(size);
722
- if (iovs === 0 || size === 0) {
756
+ if ((iovs === 0 && iovslen) || size === 0) {
723
757
  return types_1.WasiErrno.EINVAL;
724
758
  }
725
759
  const { HEAPU8, view } = getMemory(this);
726
760
  const wasi = _wasi.get(this);
727
761
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ, BigInt(0));
762
+ if (!iovslen) {
763
+ view.setUint32(size, 0, true);
764
+ return types_1.WasiErrno.ESUCCESS;
765
+ }
728
766
  let totalSize = 0;
729
767
  const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
730
768
  const offset = iovs + (i * 8);
@@ -762,12 +800,16 @@ class WASI {
762
800
  }, async function fd_read(fd, iovs, iovslen, size) {
763
801
  iovs = Number(iovs);
764
802
  size = Number(size);
765
- if (iovs === 0 || size === 0) {
803
+ if ((iovs === 0 && iovslen) || size === 0) {
766
804
  return types_1.WasiErrno.EINVAL;
767
805
  }
768
806
  const { HEAPU8, view } = getMemory(this);
769
807
  const wasi = _wasi.get(this);
770
808
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_READ, BigInt(0));
809
+ if (!iovslen) {
810
+ view.setUint32(size, 0, true);
811
+ return types_1.WasiErrno.ESUCCESS;
812
+ }
771
813
  let totalSize = 0;
772
814
  const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
773
815
  const offset = iovs + (i * 8);
@@ -920,12 +962,16 @@ class WASI {
920
962
  defineImport('fd_write', function fd_write(fd, iovs, iovslen, size) {
921
963
  iovs = Number(iovs);
922
964
  size = Number(size);
923
- if (iovs === 0 || size === 0) {
965
+ if ((iovs === 0 && iovslen) || size === 0) {
924
966
  return types_1.WasiErrno.EINVAL;
925
967
  }
926
968
  const { HEAPU8, view } = getMemory(this);
927
969
  const wasi = _wasi.get(this);
928
970
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE, BigInt(0));
971
+ if (!iovslen) {
972
+ view.setUint32(size, 0, true);
973
+ return types_1.WasiErrno.ESUCCESS;
974
+ }
929
975
  const buffer = (0, fd_1.concatBuffer)(Array.from({ length: Number(iovslen) }, (_, i) => {
930
976
  const offset = iovs + (i * 8);
931
977
  const buf = view.getInt32(offset, true);
@@ -946,12 +992,16 @@ class WASI {
946
992
  }, async function fd_write(fd, iovs, iovslen, size) {
947
993
  iovs = Number(iovs);
948
994
  size = Number(size);
949
- if (iovs === 0 || size === 0) {
995
+ if ((iovs === 0 && iovslen) || size === 0) {
950
996
  return types_1.WasiErrno.EINVAL;
951
997
  }
952
998
  const { HEAPU8, view } = getMemory(this);
953
999
  const wasi = _wasi.get(this);
954
1000
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.FD_WRITE, BigInt(0));
1001
+ if (!iovslen) {
1002
+ view.setUint32(size, 0, true);
1003
+ return types_1.WasiErrno.ESUCCESS;
1004
+ }
955
1005
  const buffer = (0, fd_1.concatBuffer)(Array.from({ length: Number(iovslen) }, (_, i) => {
956
1006
  const offset = iovs + (i * 8);
957
1007
  const buf = view.getInt32(offset, true);
@@ -1048,15 +1098,12 @@ class WASI {
1048
1098
  path_len = Number(path_len);
1049
1099
  if (path === 0)
1050
1100
  return types_1.WasiErrno.EINVAL;
1051
- if ((fst_flags) & ~(types_1.WasiFstFlag.SET_ATIM |
1052
- types_1.WasiFstFlag.SET_ATIM_NOW |
1053
- types_1.WasiFstFlag.SET_MTIM |
1054
- types_1.WasiFstFlag.SET_MTIM_NOW)) {
1055
- return types_1.WasiErrno.EINVAL;
1056
- }
1057
1101
  const { HEAPU8 } = getMemory(this);
1058
1102
  const wasi = _wasi.get(this);
1059
1103
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
1104
+ if (validateFstFlagsOrReturn(fst_flags)) {
1105
+ return types_1.WasiErrno.EINVAL;
1106
+ }
1060
1107
  const fs = getFs(this);
1061
1108
  const resolvedPath = resolvePathSync(fs, fileDescriptor, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len)), flags);
1062
1109
  if ((fst_flags & types_1.WasiFstFlag.SET_ATIM_NOW) === types_1.WasiFstFlag.SET_ATIM_NOW) {
@@ -1072,15 +1119,12 @@ class WASI {
1072
1119
  path_len = Number(path_len);
1073
1120
  if (path === 0)
1074
1121
  return types_1.WasiErrno.EINVAL;
1075
- if ((fst_flags) & ~(types_1.WasiFstFlag.SET_ATIM |
1076
- types_1.WasiFstFlag.SET_ATIM_NOW |
1077
- types_1.WasiFstFlag.SET_MTIM |
1078
- types_1.WasiFstFlag.SET_MTIM_NOW)) {
1079
- return types_1.WasiErrno.EINVAL;
1080
- }
1081
1122
  const { HEAPU8 } = getMemory(this);
1082
1123
  const wasi = _wasi.get(this);
1083
1124
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
1125
+ if (validateFstFlagsOrReturn(fst_flags)) {
1126
+ return types_1.WasiErrno.EINVAL;
1127
+ }
1084
1128
  const fs = getFs(this);
1085
1129
  const resolvedPath = await resolvePathAsync(fs, fileDescriptor, decoder.decode((0, util_1.unsharedSlice)(HEAPU8, path, path + path_len)), flags);
1086
1130
  if ((fst_flags & types_1.WasiFstFlag.SET_ATIM_NOW) === types_1.WasiFstFlag.SET_ATIM_NOW) {
@@ -1207,7 +1251,9 @@ class WASI {
1207
1251
  const resolved_path = resolvePathSync(fs, fileDescriptor, pathString, dirflags);
1208
1252
  const r = fs.openSync(resolved_path, flagsRes, 0o666);
1209
1253
  const filetype = wasi.fds.getFileTypeByFd(r);
1210
- if ((o_flags & types_1.WasiFileControlFlag.O_DIRECTORY) !== 0 && filetype !== types_1.WasiFileType.DIRECTORY) {
1254
+ if ((filetype !== types_1.WasiFileType.DIRECTORY) &&
1255
+ ((o_flags & types_1.WasiFileControlFlag.O_DIRECTORY) !== 0 ||
1256
+ (resolved_path.endsWith('/')))) {
1211
1257
  return types_1.WasiErrno.ENOTDIR;
1212
1258
  }
1213
1259
  const { base: max_base, inheriting: max_inheriting } = (0, rights_1.getRights)(wasi.fds.stdio, r, flagsRes, filetype);
@@ -1279,7 +1325,7 @@ class WASI {
1279
1325
  return types_1.WasiErrno.ENOBUFS;
1280
1326
  HEAPU8.set(linkData.subarray(0, len), buf);
1281
1327
  HEAPU8[buf + len] = 0;
1282
- view.setUint32(bufused, len + 1, true);
1328
+ view.setUint32(bufused, len, true);
1283
1329
  return types_1.WasiErrno.ESUCCESS;
1284
1330
  }, async function path_readlink(fd, path, path_len, buf, buf_len, bufused) {
1285
1331
  path = Number(path);
@@ -1303,7 +1349,7 @@ class WASI {
1303
1349
  return types_1.WasiErrno.ENOBUFS;
1304
1350
  HEAPU8.set(linkData.subarray(0, len), buf);
1305
1351
  HEAPU8[buf + len] = 0;
1306
- view.setUint32(bufused, len + 1, true);
1352
+ view.setUint32(bufused, len, true);
1307
1353
  return types_1.WasiErrno.ESUCCESS;
1308
1354
  }, ['i32', 'i32', 'i32', 'i32', 'i32', 'i32'], ['i32']);
1309
1355
  defineImport('path_remove_directory', function path_remove_directory(fd, path, path_len) {
@@ -1396,6 +1442,9 @@ class WASI {
1396
1442
  const wasi = _wasi.get(this);
1397
1443
  const fileDescriptor = wasi.fds.get(fd, types_1.WasiRights.PATH_SYMLINK, BigInt(0));
1398
1444
  const oldPath = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, old_path, old_path + old_path_len));
1445
+ if (oldPath.length > 0 && oldPath[0] === '/') {
1446
+ return types_1.WasiErrno.EPERM;
1447
+ }
1399
1448
  let newPath = decoder.decode((0, util_1.unsharedSlice)(HEAPU8, new_path, new_path + new_path_len));
1400
1449
  newPath = (0, path_1.resolve)(fileDescriptor.realPath, newPath);
1401
1450
  const fs = getFs(this);
@@ -32,7 +32,8 @@ exports.RIGHTS_ALL = types_1.WasiRights.FD_DATASYNC |
32
32
  types_1.WasiRights.PATH_UNLINK_FILE |
33
33
  types_1.WasiRights.PATH_REMOVE_DIRECTORY |
34
34
  types_1.WasiRights.POLL_FD_READWRITE |
35
- types_1.WasiRights.SOCK_SHUTDOWN;
35
+ types_1.WasiRights.SOCK_SHUTDOWN |
36
+ types_1.WasiRights.SOCK_ACCEPT;
36
37
  exports.BLOCK_DEVICE_BASE = exports.RIGHTS_ALL;
37
38
  exports.BLOCK_DEVICE_INHERITING = exports.RIGHTS_ALL;
38
39
  exports.CHARACTER_DEVICE_BASE = exports.RIGHTS_ALL;
@@ -7,12 +7,6 @@ const kSetMemory = Symbol('kSetMemory');
7
7
  const kStarted = Symbol('kStarted');
8
8
  const kInstance = Symbol('kInstance');
9
9
  const kBindingName = Symbol('kBindingName');
10
- function setupInstance(self, instance) {
11
- validateObject(instance, 'instance');
12
- validateObject(instance.exports, 'instance.exports');
13
- self[kInstance] = instance;
14
- self[kSetMemory](instance.exports.memory);
15
- }
16
10
  function validateOptions(options) {
17
11
  var _a;
18
12
  validateObject(options, 'options');
@@ -117,13 +111,21 @@ export class WASI {
117
111
  wrap.proc_exit = wasiReturnOnProcExit.bind(this);
118
112
  }
119
113
  }
120
- // Must not export _initialize, must export _start
121
- start(instance) {
114
+ finalizeBindings(instance, _a) {
115
+ var _b;
116
+ var { memory = (_b = instance === null || instance === void 0 ? void 0 : instance.exports) === null || _b === void 0 ? void 0 : _b.memory } = _a === void 0 ? {} : _a;
122
117
  if (this[kStarted]) {
123
118
  throw new Error('WASI instance has already started');
124
119
  }
120
+ validateObject(instance, 'instance');
121
+ validateObject(instance.exports, 'instance.exports');
122
+ this[kSetMemory](memory);
123
+ this[kInstance] = instance;
125
124
  this[kStarted] = true;
126
- setupInstance(this, instance);
125
+ }
126
+ // Must not export _initialize, must export _start
127
+ start(instance) {
128
+ this.finalizeBindings(instance);
127
129
  const { _start, _initialize } = this[kInstance].exports;
128
130
  validateFunction(_start, 'instance.exports._start');
129
131
  validateUndefined(_initialize, 'instance.exports._initialize');
@@ -148,11 +150,7 @@ export class WASI {
148
150
  }
149
151
  // Must not export _start, may optionally export _initialize
150
152
  initialize(instance) {
151
- if (this[kStarted]) {
152
- throw new Error('WASI instance has already started');
153
- }
154
- this[kStarted] = true;
155
- setupInstance(this, instance);
153
+ this.finalizeBindings(instance);
156
154
  const { _start, _initialize } = this[kInstance].exports;
157
155
  validateUndefined(_start, 'instance.exports._start');
158
156
  if (_initialize !== undefined) {
@@ -118,6 +118,7 @@ async function resolvePathAsync(fs, fileDescriptor, path, flags) {
118
118
  const encoder = /*#__PURE__*/ new TextEncoder();
119
119
  // eslint-disable-next-line spaced-comment
120
120
  const decoder = /*#__PURE__*/ new TextDecoder();
121
+ const INT64_MAX = (BigInt(1) << BigInt(63)) - BigInt(1);
121
122
  function readStdin() {
122
123
  const value = window.prompt();
123
124
  if (value === null)
@@ -125,6 +126,14 @@ function readStdin() {
125
126
  const buffer = new TextEncoder().encode(value + '\n');
126
127
  return buffer;
127
128
  }
129
+ function validateFstFlagsOrReturn(flags) {
130
+ return (Boolean((flags) & ~(WasiFstFlag.SET_ATIM | WasiFstFlag.SET_ATIM_NOW |
131
+ WasiFstFlag.SET_MTIM | WasiFstFlag.SET_MTIM_NOW)) ||
132
+ ((flags) & (WasiFstFlag.SET_ATIM | WasiFstFlag.SET_ATIM_NOW)) ===
133
+ (WasiFstFlag.SET_ATIM | WasiFstFlag.SET_ATIM_NOW) ||
134
+ ((flags) & (WasiFstFlag.SET_MTIM | WasiFstFlag.SET_MTIM_NOW)) ===
135
+ (WasiFstFlag.SET_MTIM | WasiFstFlag.SET_MTIM_NOW));
136
+ }
128
137
  export class WASI {
129
138
  constructor(args, env, fds, asyncFs, fs, asyncify) {
130
139
  this.args_get = syscallWrap(this, 'args_get', function (argv, argv_buf) {
@@ -221,7 +230,7 @@ export class WASI {
221
230
  case WasiClockid.MONOTONIC:
222
231
  case WasiClockid.PROCESS_CPUTIME_ID:
223
232
  case WasiClockid.THREAD_CPUTIME_ID: {
224
- const t = performance.now();
233
+ const t = performance.now() / 1000;
225
234
  const s = Math.trunc(t);
226
235
  const ms = Math.floor((t - s) * 1000);
227
236
  const result = BigInt(s) * BigInt(1000000000) + BigInt(ms) * BigInt(1000000);
@@ -285,7 +294,7 @@ export class WASI {
285
294
  const { view } = getMemory(this);
286
295
  // preopen type is dir(0)
287
296
  view.setUint32(prestat, 0, true);
288
- view.setUint32(prestat + 4, encoder.encode(fileDescriptor.path).length + 1, true);
297
+ view.setUint32(prestat + 4, encoder.encode(fileDescriptor.path).length, true);
289
298
  return WasiErrno.ESUCCESS;
290
299
  });
291
300
  this.fd_prestat_dir_name = syscallWrap(this, 'fd_prestat_dir_name', function (fd, path, path_len) {
@@ -298,7 +307,7 @@ export class WASI {
298
307
  const fileDescriptor = wasi.fds.get(fd, BigInt(0), BigInt(0));
299
308
  if (fileDescriptor.preopen !== 1)
300
309
  return WasiErrno.EBADF;
301
- const buffer = encoder.encode(fileDescriptor.path + '\0');
310
+ const buffer = encoder.encode(fileDescriptor.path);
302
311
  const size = buffer.length;
303
312
  if (size > path_len)
304
313
  return WasiErrno.ENOBUFS;
@@ -493,6 +502,9 @@ export class WASI {
493
502
  this.sock_shutdown = syscallWrap(this, 'sock_shutdown', function () {
494
503
  return WasiErrno.ENOTSUP;
495
504
  });
505
+ this.sock_accept = syscallWrap(this, 'sock_accept', function () {
506
+ return WasiErrno.ENOTSUP;
507
+ });
496
508
  _wasi.set(this, {
497
509
  fds,
498
510
  args,
@@ -608,11 +620,17 @@ export class WASI {
608
620
  return { fileDescriptor, atim, mtim };
609
621
  }
610
622
  defineImport('fd_filestat_set_times', function fd_filestat_set_times(fd, atim, mtim, flags) {
623
+ if (validateFstFlagsOrReturn(flags)) {
624
+ return WasiErrno.EINVAL;
625
+ }
611
626
  const { fileDescriptor, atim: atimRes, mtim: mtimRes } = fdFilestatGetTimes.call(this, fd, atim, mtim, flags);
612
627
  const fs = getFs(this);
613
628
  fs.futimesSync(fileDescriptor.fd, Number(atimRes), Number(mtimRes));
614
629
  return WasiErrno.ESUCCESS;
615
630
  }, async function fd_filestat_set_times(fd, atim, mtim, flags) {
631
+ if (validateFstFlagsOrReturn(flags)) {
632
+ return WasiErrno.EINVAL;
633
+ }
616
634
  const { fileDescriptor, atim: atimRes, mtim: mtimRes } = fdFilestatGetTimes.call(this, fd, atim, mtim, flags);
617
635
  const h = fileDescriptor.fd;
618
636
  await h.utimes(Number(atimRes), Number(mtimRes));
@@ -621,12 +639,16 @@ export class WASI {
621
639
  defineImport('fd_pread', function fd_pread(fd, iovs, iovslen, offset, size) {
622
640
  iovs = Number(iovs);
623
641
  size = Number(size);
624
- if (iovs === 0 || size === 0) {
642
+ if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
625
643
  return WasiErrno.EINVAL;
626
644
  }
627
645
  const { HEAPU8, view } = getMemory(this);
628
646
  const wasi = _wasi.get(this);
629
647
  const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_READ | WasiRights.FD_SEEK, BigInt(0));
648
+ if (!iovslen) {
649
+ view.setUint32(size, 0, true);
650
+ return WasiErrno.ESUCCESS;
651
+ }
630
652
  let totalSize = 0;
631
653
  const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
632
654
  const offset = iovs + (i * 8);
@@ -653,12 +675,16 @@ export class WASI {
653
675
  }, async function (fd, iovs, iovslen, offset, size) {
654
676
  iovs = Number(iovs);
655
677
  size = Number(size);
656
- if (iovs === 0 || size === 0) {
678
+ if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
657
679
  return WasiErrno.EINVAL;
658
680
  }
659
681
  const { HEAPU8, view } = getMemory(this);
660
682
  const wasi = _wasi.get(this);
661
683
  const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_READ | WasiRights.FD_SEEK, BigInt(0));
684
+ if (!iovslen) {
685
+ view.setUint32(size, 0, true);
686
+ return WasiErrno.ESUCCESS;
687
+ }
662
688
  let totalSize = 0;
663
689
  const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
664
690
  const offset = iovs + (i * 8);
@@ -678,12 +704,16 @@ export class WASI {
678
704
  defineImport('fd_pwrite', function fd_pwrite(fd, iovs, iovslen, offset, size) {
679
705
  iovs = Number(iovs);
680
706
  size = Number(size);
681
- if (iovs === 0 || size === 0) {
707
+ if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
682
708
  return WasiErrno.EINVAL;
683
709
  }
684
710
  const { HEAPU8, view } = getMemory(this);
685
711
  const wasi = _wasi.get(this);
686
712
  const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_WRITE | WasiRights.FD_SEEK, BigInt(0));
713
+ if (!iovslen) {
714
+ view.setUint32(size, 0, true);
715
+ return WasiErrno.ESUCCESS;
716
+ }
687
717
  const buffer = concatBuffer(Array.from({ length: Number(iovslen) }, (_, i) => {
688
718
  const offset = iovs + (i * 8);
689
719
  const buf = view.getInt32(offset, true);
@@ -697,12 +727,16 @@ export class WASI {
697
727
  }, async function fd_pwrite(fd, iovs, iovslen, offset, size) {
698
728
  iovs = Number(iovs);
699
729
  size = Number(size);
700
- if (iovs === 0 || size === 0) {
730
+ if ((iovs === 0 && iovslen) || size === 0 || offset > INT64_MAX) {
701
731
  return WasiErrno.EINVAL;
702
732
  }
703
733
  const { HEAPU8, view } = getMemory(this);
704
734
  const wasi = _wasi.get(this);
705
735
  const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_WRITE | WasiRights.FD_SEEK, BigInt(0));
736
+ if (!iovslen) {
737
+ view.setUint32(size, 0, true);
738
+ return WasiErrno.ESUCCESS;
739
+ }
706
740
  const buffer = concatBuffer(Array.from({ length: Number(iovslen) }, (_, i) => {
707
741
  const offset = iovs + (i * 8);
708
742
  const buf = view.getInt32(offset, true);
@@ -716,12 +750,16 @@ export class WASI {
716
750
  defineImport('fd_read', function fd_read(fd, iovs, iovslen, size) {
717
751
  iovs = Number(iovs);
718
752
  size = Number(size);
719
- if (iovs === 0 || size === 0) {
753
+ if ((iovs === 0 && iovslen) || size === 0) {
720
754
  return WasiErrno.EINVAL;
721
755
  }
722
756
  const { HEAPU8, view } = getMemory(this);
723
757
  const wasi = _wasi.get(this);
724
758
  const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_READ, BigInt(0));
759
+ if (!iovslen) {
760
+ view.setUint32(size, 0, true);
761
+ return WasiErrno.ESUCCESS;
762
+ }
725
763
  let totalSize = 0;
726
764
  const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
727
765
  const offset = iovs + (i * 8);
@@ -759,12 +797,16 @@ export class WASI {
759
797
  }, async function fd_read(fd, iovs, iovslen, size) {
760
798
  iovs = Number(iovs);
761
799
  size = Number(size);
762
- if (iovs === 0 || size === 0) {
800
+ if ((iovs === 0 && iovslen) || size === 0) {
763
801
  return WasiErrno.EINVAL;
764
802
  }
765
803
  const { HEAPU8, view } = getMemory(this);
766
804
  const wasi = _wasi.get(this);
767
805
  const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_READ, BigInt(0));
806
+ if (!iovslen) {
807
+ view.setUint32(size, 0, true);
808
+ return WasiErrno.ESUCCESS;
809
+ }
768
810
  let totalSize = 0;
769
811
  const ioVecs = Array.from({ length: Number(iovslen) }, (_, i) => {
770
812
  const offset = iovs + (i * 8);
@@ -917,12 +959,16 @@ export class WASI {
917
959
  defineImport('fd_write', function fd_write(fd, iovs, iovslen, size) {
918
960
  iovs = Number(iovs);
919
961
  size = Number(size);
920
- if (iovs === 0 || size === 0) {
962
+ if ((iovs === 0 && iovslen) || size === 0) {
921
963
  return WasiErrno.EINVAL;
922
964
  }
923
965
  const { HEAPU8, view } = getMemory(this);
924
966
  const wasi = _wasi.get(this);
925
967
  const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_WRITE, BigInt(0));
968
+ if (!iovslen) {
969
+ view.setUint32(size, 0, true);
970
+ return WasiErrno.ESUCCESS;
971
+ }
926
972
  const buffer = concatBuffer(Array.from({ length: Number(iovslen) }, (_, i) => {
927
973
  const offset = iovs + (i * 8);
928
974
  const buf = view.getInt32(offset, true);
@@ -943,12 +989,16 @@ export class WASI {
943
989
  }, async function fd_write(fd, iovs, iovslen, size) {
944
990
  iovs = Number(iovs);
945
991
  size = Number(size);
946
- if (iovs === 0 || size === 0) {
992
+ if ((iovs === 0 && iovslen) || size === 0) {
947
993
  return WasiErrno.EINVAL;
948
994
  }
949
995
  const { HEAPU8, view } = getMemory(this);
950
996
  const wasi = _wasi.get(this);
951
997
  const fileDescriptor = wasi.fds.get(fd, WasiRights.FD_WRITE, BigInt(0));
998
+ if (!iovslen) {
999
+ view.setUint32(size, 0, true);
1000
+ return WasiErrno.ESUCCESS;
1001
+ }
952
1002
  const buffer = concatBuffer(Array.from({ length: Number(iovslen) }, (_, i) => {
953
1003
  const offset = iovs + (i * 8);
954
1004
  const buf = view.getInt32(offset, true);
@@ -1045,15 +1095,12 @@ export class WASI {
1045
1095
  path_len = Number(path_len);
1046
1096
  if (path === 0)
1047
1097
  return WasiErrno.EINVAL;
1048
- if ((fst_flags) & ~(WasiFstFlag.SET_ATIM |
1049
- WasiFstFlag.SET_ATIM_NOW |
1050
- WasiFstFlag.SET_MTIM |
1051
- WasiFstFlag.SET_MTIM_NOW)) {
1052
- return WasiErrno.EINVAL;
1053
- }
1054
1098
  const { HEAPU8 } = getMemory(this);
1055
1099
  const wasi = _wasi.get(this);
1056
1100
  const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
1101
+ if (validateFstFlagsOrReturn(fst_flags)) {
1102
+ return WasiErrno.EINVAL;
1103
+ }
1057
1104
  const fs = getFs(this);
1058
1105
  const resolvedPath = resolvePathSync(fs, fileDescriptor, decoder.decode(unsharedSlice(HEAPU8, path, path + path_len)), flags);
1059
1106
  if ((fst_flags & WasiFstFlag.SET_ATIM_NOW) === WasiFstFlag.SET_ATIM_NOW) {
@@ -1069,15 +1116,12 @@ export class WASI {
1069
1116
  path_len = Number(path_len);
1070
1117
  if (path === 0)
1071
1118
  return WasiErrno.EINVAL;
1072
- if ((fst_flags) & ~(WasiFstFlag.SET_ATIM |
1073
- WasiFstFlag.SET_ATIM_NOW |
1074
- WasiFstFlag.SET_MTIM |
1075
- WasiFstFlag.SET_MTIM_NOW)) {
1076
- return WasiErrno.EINVAL;
1077
- }
1078
1119
  const { HEAPU8 } = getMemory(this);
1079
1120
  const wasi = _wasi.get(this);
1080
1121
  const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_FILESTAT_SET_TIMES, BigInt(0));
1122
+ if (validateFstFlagsOrReturn(fst_flags)) {
1123
+ return WasiErrno.EINVAL;
1124
+ }
1081
1125
  const fs = getFs(this);
1082
1126
  const resolvedPath = await resolvePathAsync(fs, fileDescriptor, decoder.decode(unsharedSlice(HEAPU8, path, path + path_len)), flags);
1083
1127
  if ((fst_flags & WasiFstFlag.SET_ATIM_NOW) === WasiFstFlag.SET_ATIM_NOW) {
@@ -1204,7 +1248,9 @@ export class WASI {
1204
1248
  const resolved_path = resolvePathSync(fs, fileDescriptor, pathString, dirflags);
1205
1249
  const r = fs.openSync(resolved_path, flagsRes, 0o666);
1206
1250
  const filetype = wasi.fds.getFileTypeByFd(r);
1207
- if ((o_flags & WasiFileControlFlag.O_DIRECTORY) !== 0 && filetype !== WasiFileType.DIRECTORY) {
1251
+ if ((filetype !== WasiFileType.DIRECTORY) &&
1252
+ ((o_flags & WasiFileControlFlag.O_DIRECTORY) !== 0 ||
1253
+ (resolved_path.endsWith('/')))) {
1208
1254
  return WasiErrno.ENOTDIR;
1209
1255
  }
1210
1256
  const { base: max_base, inheriting: max_inheriting } = getRights(wasi.fds.stdio, r, flagsRes, filetype);
@@ -1276,7 +1322,7 @@ export class WASI {
1276
1322
  return WasiErrno.ENOBUFS;
1277
1323
  HEAPU8.set(linkData.subarray(0, len), buf);
1278
1324
  HEAPU8[buf + len] = 0;
1279
- view.setUint32(bufused, len + 1, true);
1325
+ view.setUint32(bufused, len, true);
1280
1326
  return WasiErrno.ESUCCESS;
1281
1327
  }, async function path_readlink(fd, path, path_len, buf, buf_len, bufused) {
1282
1328
  path = Number(path);
@@ -1300,7 +1346,7 @@ export class WASI {
1300
1346
  return WasiErrno.ENOBUFS;
1301
1347
  HEAPU8.set(linkData.subarray(0, len), buf);
1302
1348
  HEAPU8[buf + len] = 0;
1303
- view.setUint32(bufused, len + 1, true);
1349
+ view.setUint32(bufused, len, true);
1304
1350
  return WasiErrno.ESUCCESS;
1305
1351
  }, ['i32', 'i32', 'i32', 'i32', 'i32', 'i32'], ['i32']);
1306
1352
  defineImport('path_remove_directory', function path_remove_directory(fd, path, path_len) {
@@ -1393,6 +1439,9 @@ export class WASI {
1393
1439
  const wasi = _wasi.get(this);
1394
1440
  const fileDescriptor = wasi.fds.get(fd, WasiRights.PATH_SYMLINK, BigInt(0));
1395
1441
  const oldPath = decoder.decode(unsharedSlice(HEAPU8, old_path, old_path + old_path_len));
1442
+ if (oldPath.length > 0 && oldPath[0] === '/') {
1443
+ return WasiErrno.EPERM;
1444
+ }
1396
1445
  let newPath = decoder.decode(unsharedSlice(HEAPU8, new_path, new_path + new_path_len));
1397
1446
  newPath = resolve(fileDescriptor.realPath, newPath);
1398
1447
  const fs = getFs(this);
@@ -28,7 +28,8 @@ export const RIGHTS_ALL = WasiRights.FD_DATASYNC |
28
28
  WasiRights.PATH_UNLINK_FILE |
29
29
  WasiRights.PATH_REMOVE_DIRECTORY |
30
30
  WasiRights.POLL_FD_READWRITE |
31
- WasiRights.SOCK_SHUTDOWN;
31
+ WasiRights.SOCK_SHUTDOWN |
32
+ WasiRights.SOCK_ACCEPT;
32
33
  export const BLOCK_DEVICE_BASE = RIGHTS_ALL;
33
34
  export const BLOCK_DEVICE_INHERITING = RIGHTS_ALL;
34
35
  export const CHARACTER_DEVICE_BASE = RIGHTS_ALL;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tybys/wasm-util",
3
- "version": "0.8.3",
3
+ "version": "0.10.0",
4
4
  "description": "WASI polyfill for browser and some wasm util",
5
5
  "main": "./lib/cjs/index.js",
6
6
  "module": "./dist/wasm-util.esm-bundler.js",