Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5c33f5b

Browse files
committedOct 31, 2019
wasi: port more wasi libc integration tests
This commit ports the following tests from nodejs/node#27850. - clock_getres - getentropy (currently disabled) - getrusage - gettimeofday - notdir - preopen_populates - read_file_twice - stat - stdin - write_file This commit completes the implementations of fd_filestat_get() and path_filestat_get(), which are needed for the stat test. This commit also adds clock_res_get() and partial clock_time_get() support.
1 parent a921d15 commit 5c33f5b

24 files changed

+293
-26
lines changed
 

‎deps/uvwasi/src/uvwasi.c

+40-22
Original file line numberDiff line numberDiff line change
@@ -348,49 +348,67 @@ uvwasi_errno_t uvwasi_args_sizes_get(uvwasi_t* uvwasi,
348348
uvwasi_errno_t uvwasi_clock_res_get(uvwasi_t* uvwasi,
349349
uvwasi_clockid_t clock_id,
350350
uvwasi_timestamp_t* resolution) {
351+
#ifndef _WIN32
352+
struct timespec ts;
353+
clockid_t clk;
354+
#endif /* _WIN32 */
355+
351356
if (uvwasi == NULL || resolution == NULL)
352357
return UVWASI_EINVAL;
353358

354-
/*
355-
if (clock_id == UVWASI_CLOCK_MONOTONIC) {
356-
357-
} else if (clock_id == UVWASI_CLOCK_PROCESS_CPUTIME_ID) {
358-
359-
} else if (clock_id == UVWASI_CLOCK_REALTIME) {
359+
if (clock_id == UVWASI_CLOCK_MONOTONIC ||
360+
clock_id == UVWASI_CLOCK_REALTIME) {
361+
*resolution = 1; // Nanosecond precision.
362+
return UVWASI_ESUCCESS;
363+
} else if (clock_id == UVWASI_CLOCK_PROCESS_CPUTIME_ID ||
364+
clock_id == UVWASI_CLOCK_THREAD_CPUTIME_ID) {
365+
#ifndef _WIN32
366+
if (clock_id == UVWASI_CLOCK_PROCESS_CPUTIME_ID)
367+
clk = CLOCK_PROCESS_CPUTIME_ID;
368+
else
369+
clk = CLOCK_THREAD_CPUTIME_ID;
360370

361-
} else if (clock_id == UVWASI_CLOCK_THREAD_CPUTIME_ID) {
371+
if (clock_getres(clk, &ts) < 0)
372+
return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
362373

363-
} else {
364-
return UVWASI_EINVAL;
374+
*resolution = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec;
375+
return UVWASI_ESUCCESS;
376+
#else
377+
return UVWASI_ENOSYS;
378+
#endif /* _WIN32 */
365379
}
366-
*/
367380

368-
return UVWASI_ENOTSUP;
381+
return UVWASI_EINVAL;
369382
}
370383

371384

372385
uvwasi_errno_t uvwasi_clock_time_get(uvwasi_t* uvwasi,
373386
uvwasi_clockid_t clock_id,
374387
uvwasi_timestamp_t precision,
375388
uvwasi_timestamp_t* time) {
389+
uv_timeval64_t tv;
390+
int r;
391+
376392
if (uvwasi == NULL || time == NULL)
377393
return UVWASI_EINVAL;
378394

379-
/*
380395
if (clock_id == UVWASI_CLOCK_MONOTONIC) {
381-
382-
} else if (clock_id == UVWASI_CLOCK_PROCESS_CPUTIME_ID) {
383-
396+
*time = uv_hrtime();
397+
return UVWASI_ESUCCESS;
384398
} else if (clock_id == UVWASI_CLOCK_REALTIME) {
385-
386-
} else if (clock_id == UVWASI_CLOCK_THREAD_CPUTIME_ID) {
387-
388-
} else {
389-
return UVWASI_EINVAL;
399+
r = uv_gettimeofday(&tv);
400+
if (r != 0)
401+
return uvwasi__translate_uv_error(r);
402+
403+
*time = (tv.tv_sec * NANOS_PER_SEC) + (tv.tv_usec * 1000);
404+
return UVWASI_ESUCCESS;
405+
} else if (clock_id == UVWASI_CLOCK_PROCESS_CPUTIME_ID ||
406+
clock_id == UVWASI_CLOCK_THREAD_CPUTIME_ID) {
407+
/* TODO(cjihrig): Implement these two clocks. */
408+
return UVWASI_ENOSYS;
390409
}
391-
*/
392410

393-
return UVWASI_ENOTSUP;
411+
return UVWASI_EINVAL;
394412
}
395413

396414

‎src/node_wasi.cc

+35-2
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,23 @@ void WASI::FdFilestatGet(const FunctionCallbackInfo<Value>& args) {
444444
uvwasi_filestat_t stats;
445445
uvwasi_errno_t err = uvwasi_fd_filestat_get(&wasi->uvw_, fd, &stats);
446446

447-
// TODO(cjihrig): Check for buffer overflow and write result to memory.
447+
// TODO(cjihrig): Check for buffer overflows.
448+
if (err == UVWASI_ESUCCESS)
449+
err = wasi->writeUInt64(stats.st_dev, buf);
450+
if (err == UVWASI_ESUCCESS)
451+
err = wasi->writeUInt64(stats.st_ino, buf + 8);
452+
if (err == UVWASI_ESUCCESS)
453+
err = wasi->writeUInt8(stats.st_filetype, buf + 16);
454+
if (err == UVWASI_ESUCCESS)
455+
err = wasi->writeUInt32(stats.st_nlink, buf + 20);
456+
if (err == UVWASI_ESUCCESS)
457+
err = wasi->writeUInt64(stats.st_size, buf + 24);
458+
if (err == UVWASI_ESUCCESS)
459+
err = wasi->writeUInt64(stats.st_atim, buf + 32);
460+
if (err == UVWASI_ESUCCESS)
461+
err = wasi->writeUInt64(stats.st_mtim, buf + 40);
462+
if (err == UVWASI_ESUCCESS)
463+
err = wasi->writeUInt64(stats.st_ctim, buf + 48);
448464

449465
args.GetReturnValue().Set(err);
450466
}
@@ -884,7 +900,24 @@ void WASI::PathFilestatGet(const FunctionCallbackInfo<Value>& args) {
884900
&memory[path_ptr],
885901
path_len,
886902
&stats);
887-
// TODO(cjihrig): Check for buffer overflows and write output.
903+
// TODO(cjihrig): Check for buffer overflows.
904+
if (err == UVWASI_ESUCCESS)
905+
err = wasi->writeUInt64(stats.st_dev, buf_ptr);
906+
if (err == UVWASI_ESUCCESS)
907+
err = wasi->writeUInt64(stats.st_ino, buf_ptr + 8);
908+
if (err == UVWASI_ESUCCESS)
909+
err = wasi->writeUInt8(stats.st_filetype, buf_ptr + 16);
910+
if (err == UVWASI_ESUCCESS)
911+
err = wasi->writeUInt32(stats.st_nlink, buf_ptr + 20);
912+
if (err == UVWASI_ESUCCESS)
913+
err = wasi->writeUInt64(stats.st_size, buf_ptr + 24);
914+
if (err == UVWASI_ESUCCESS)
915+
err = wasi->writeUInt64(stats.st_atim, buf_ptr + 32);
916+
if (err == UVWASI_ESUCCESS)
917+
err = wasi->writeUInt64(stats.st_mtim, buf_ptr + 40);
918+
if (err == UVWASI_ESUCCESS)
919+
err = wasi->writeUInt64(stats.st_ctim, buf_ptr + 48);
920+
888921
args.GetReturnValue().Set(err);
889922
}
890923

‎test/fixtures/wasi/notadir

Whitespace-only changes.

‎test/wasi/c/clock_getres.c

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <assert.h>
2+
#include <time.h>
3+
4+
int main() {
5+
struct timespec ts;
6+
int r;
7+
8+
// supported clocks
9+
r = clock_getres(CLOCK_REALTIME, &ts);
10+
assert(r == 0);
11+
r = clock_getres(CLOCK_MONOTONIC, &ts);
12+
assert(r == 0);
13+
r = clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
14+
assert(r == 0);
15+
r = clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts);
16+
assert(r == 0);
17+
}

‎test/wasi/c/getentropy.c

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <assert.h>
2+
#include <unistd.h>
3+
4+
int main() {
5+
char buf[256] = {0};
6+
int r = getentropy(buf, 256);
7+
assert(r == 0);
8+
9+
for (int i = 0; i < 256; i++) {
10+
if (buf[i] != 0) {
11+
return 0;
12+
}
13+
}
14+
15+
// if this ever is reached, we either have a bug or should buy a lottery
16+
// ticket
17+
return 1;
18+
}

‎test/wasi/c/getrusage.c

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <assert.h>
2+
#include <sys/resource.h>
3+
4+
int main() {
5+
struct rusage ru1;
6+
getrusage(RUSAGE_SELF, &ru1);
7+
8+
for (int i = 0; i < 1000; i++) {
9+
}
10+
11+
struct rusage ru2;
12+
getrusage(RUSAGE_SELF, &ru2);
13+
14+
// assert that some time has passed
15+
long long s1 = ru1.ru_utime.tv_sec;
16+
long long us1 = ru1.ru_utime.tv_usec;
17+
long long s2 = ru2.ru_utime.tv_sec;
18+
long long us2 = ru2.ru_utime.tv_usec;
19+
assert(s1 <= s2);
20+
if (s1 == s2) {
21+
// strictly less than, so the timestamps can't be equal
22+
assert(us1 < us2);
23+
}
24+
}

‎test/wasi/c/gettimeofday.c

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
#include <sys/time.h>
4+
5+
int main() {
6+
struct timeval tv1;
7+
gettimeofday(&tv1, NULL);
8+
9+
for (int i = 0; i < 1000; i++) {
10+
}
11+
12+
struct timeval tv2;
13+
gettimeofday(&tv2, NULL);
14+
15+
// assert that some time has passed
16+
long long s1 = tv1.tv_sec;
17+
long long us1 = tv1.tv_usec;
18+
long long s2 = tv2.tv_sec;
19+
long long us2 = tv2.tv_usec;
20+
assert(s1 <= s2);
21+
if (s1 == s2) {
22+
// strictly less than, so the timestamps can't be equal
23+
assert(us1 < us2);
24+
}
25+
}

‎test/wasi/c/notdir.c

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <assert.h>
2+
#include <dirent.h>
3+
#include <errno.h>
4+
5+
int main() {
6+
DIR* dir = opendir("/sandbox/notadir");
7+
assert(dir == NULL);
8+
assert(errno == ENOTDIR);
9+
10+
return 0;
11+
}

‎test/wasi/c/preopen_populates.c

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
int main(void) {
2+
return 0;
3+
}

‎test/wasi/c/read_file_twice.c

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <assert.h>
2+
#include <stdio.h>
3+
4+
int main() {
5+
for (int i = 0; i < 2; i++) {
6+
FILE* file = fopen("/sandbox/input.txt", "r");
7+
assert(file != NULL);
8+
9+
char c = fgetc(file);
10+
while (c != EOF) {
11+
int wrote = fputc(c, stdout);
12+
assert(wrote != EOF);
13+
c = fgetc(file);
14+
}
15+
}
16+
}

‎test/wasi/c/stat.c

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <sys/stat.h>
2+
3+
#include <assert.h>
4+
#include <fcntl.h>
5+
#include <time.h>
6+
#include <unistd.h>
7+
8+
#define BASE_DIR "/tmp"
9+
#define OUTPUT_DIR BASE_DIR "/testdir"
10+
#define PATH OUTPUT_DIR "/output.txt"
11+
#define SIZE 500
12+
13+
int main(void) {
14+
struct stat st;
15+
int fd;
16+
int ret;
17+
off_t pos;
18+
19+
(void)st;
20+
ret = mkdir(OUTPUT_DIR, 0755);
21+
assert(ret == 0);
22+
23+
fd = open(PATH, O_CREAT | O_WRONLY, 0666);
24+
assert(fd != -1);
25+
26+
pos = lseek(fd, SIZE - 1, SEEK_SET);
27+
assert(pos == SIZE - 1);
28+
29+
ret = (int)write(fd, "", 1);
30+
assert(ret == 1);
31+
32+
ret = fstat(fd, &st);
33+
assert(ret == 0);
34+
assert(st.st_size == SIZE);
35+
36+
ret = close(fd);
37+
assert(ret == 0);
38+
39+
ret = access(PATH, R_OK);
40+
assert(ret == 0);
41+
42+
ret = stat(PATH, &st);
43+
assert(ret == 0);
44+
assert(st.st_size == SIZE);
45+
46+
ret = unlink(PATH);
47+
assert(ret == 0);
48+
49+
ret = stat(PATH, &st);
50+
assert(ret == -1);
51+
52+
return 0;
53+
}

‎test/wasi/c/stdin.c

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <stdio.h>
2+
3+
int main(void) {
4+
char x[32];
5+
6+
if (fgets(x, sizeof x, stdin) == NULL) {
7+
return ferror(stdin);
8+
}
9+
if (fputs(x, stdout) == EOF) {
10+
return ferror(stdout);
11+
}
12+
return 0;
13+
}

‎test/wasi/c/write_file.c

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <assert.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
5+
static char* message = "hello, file!";
6+
7+
int main() {
8+
FILE* file = fopen("/tmp/output.txt", "w");
9+
assert(file != NULL);
10+
11+
int nwritten = fprintf(file, "%s", message);
12+
assert(nwritten == strlen(message));
13+
int r = fclose(file);
14+
assert(r == 0);
15+
}

‎test/wasi/test-wasi.js

+23-2
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@ require('../common');
33

44
if (process.argv[2] === 'wasi-child') {
55
const fixtures = require('../common/fixtures');
6+
const tmpdir = require('../../test/common/tmpdir');
67
const fs = require('fs');
78
const path = require('path');
89
const { WASI } = require('wasi');
10+
tmpdir.refresh();
911
const wasmDir = path.join(__dirname, 'wasm');
1012
const wasi = new WASI({
1113
args: [],
1214
env: process.env,
1315
preopens: {
14-
'/sandbox': fixtures.path('wasi')
16+
'/sandbox': fixtures.path('wasi'),
17+
'/tmp': tmpdir.path
1518
}
1619
});
1720
const importObject = { wasi_unstable: wasi.wasiImport };
@@ -29,20 +32,38 @@ if (process.argv[2] === 'wasi-child') {
2932

3033
function runWASI(options) {
3134
console.log('executing', options.test);
35+
const opts = {};
36+
37+
if (options.stdin !== undefined)
38+
opts.input = options.stdin;
39+
3240
const child = cp.spawnSync(process.execPath, [
3341
'--experimental-wasm-bigint',
3442
__filename,
3543
'wasi-child',
3644
options.test
37-
]);
45+
], opts);
3846

3947
assert.strictEqual(child.status, options.exitCode || 0);
4048
assert.strictEqual(child.signal, null);
4149
assert.strictEqual(child.stdout.toString(), options.stdout || '');
4250
}
4351

4452
runWASI({ test: 'cant_dotdot' });
53+
runWASI({ test: 'clock_getres' });
4554
runWASI({ test: 'exitcode', exitCode: 120 });
4655
runWASI({ test: 'fd_prestat_get_refresh' });
56+
// runWASI({ test: 'getentropy' });
57+
runWASI({ test: 'getrusage' });
58+
runWASI({ test: 'gettimeofday' });
59+
runWASI({ test: 'notdir' });
60+
runWASI({ test: 'preopen_populates' });
4761
runWASI({ test: 'read_file', stdout: 'hello from input.txt\n' });
62+
runWASI({
63+
test: 'read_file_twice',
64+
stdout: 'hello from input.txt\nhello from input.txt\n'
65+
});
66+
runWASI({ test: 'stat' });
67+
runWASI({ test: 'stdin', stdin: 'hello world', stdout: 'hello world' });
68+
runWASI({ test: 'write_file' });
4869
}

‎test/wasi/wasm/clock_getres.wasm

29.4 KB
Binary file not shown.

‎test/wasi/wasm/getentropy.wasm

29.2 KB
Binary file not shown.

‎test/wasi/wasm/getrusage.wasm

29.6 KB
Binary file not shown.

‎test/wasi/wasm/gettimeofday.wasm

29.5 KB
Binary file not shown.

‎test/wasi/wasm/notdir.wasm

30.5 KB
Binary file not shown.

‎test/wasi/wasm/preopen_populates.wasm

12.4 KB
Binary file not shown.

‎test/wasi/wasm/read_file_twice.wasm

34.2 KB
Binary file not shown.

‎test/wasi/wasm/stat.wasm

33.7 KB
Binary file not shown.

‎test/wasi/wasm/stdin.wasm

18 KB
Binary file not shown.

‎test/wasi/wasm/write_file.wasm

32.6 KB
Binary file not shown.

0 commit comments

Comments
 (0)
This repository has been archived.