summaryrefslogtreecommitdiffstats
path: root/third_party/rust/lucet-wasi-wasmsbx/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/lucet-wasi-wasmsbx/tests
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/lucet-wasi-wasmsbx/tests')
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/cant_dotdot.c12
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/clock_getres.c13
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/duplicate_import.wat38
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/exitcode.c4
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/follow_symlink.c14
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/fs.c158
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/getentropy.c17
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/getrusage.c30
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/gettimeofday.c26
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/notdir.c12
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/poll.c32
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/preopen_populates.c4
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file.c14
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file_twice.c16
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/stat.c54
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/stdin.c10
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_escape.c10
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_loop.c10
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/write_file.c16
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/test_helpers/mod.rs127
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/tests.rs405
21 files changed, 1022 insertions, 0 deletions
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/cant_dotdot.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/cant_dotdot.c
new file mode 100644
index 0000000000..12b6ce78c9
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/cant_dotdot.c
@@ -0,0 +1,12 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/../outside.txt", "r");
+ assert(file == NULL);
+ assert(errno == ENOTCAPABLE);
+
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/clock_getres.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/clock_getres.c
new file mode 100644
index 0000000000..27a9f46472
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/clock_getres.c
@@ -0,0 +1,13 @@
+#include <assert.h>
+#include <time.h>
+
+int main()
+{
+ struct timespec ts;
+
+ // supported clocks
+ assert(clock_getres(CLOCK_REALTIME, &ts) == 0);
+ assert(clock_getres(CLOCK_MONOTONIC, &ts) == 0);
+ assert(clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0);
+ assert(clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts) == 0);
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/duplicate_import.wat b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/duplicate_import.wat
new file mode 100644
index 0000000000..6bd7c1eeca
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/duplicate_import.wat
@@ -0,0 +1,38 @@
+(module
+ (type (func (param i32 i32 i32 i32) (result i32)))
+ (type (func (result i32)))
+
+ ;; import fd_read, this is fine.
+ (func $read (import "wasi_unstable" "fd_read") (type 0))
+
+ ;; import fd_write, this is also fine.
+ (func $write (import "wasi_unstable" "fd_write") (type 0))
+
+ ;; import fd_read, again, under a different name!
+ ;; this is to test that we join together the imports.
+ ;; the .wat would be invalid if their types disagree, so there
+ ;; is no observable difference between $read and $read_2
+ (func $read_2 (import "wasi_unstable" "fd_read") (type 0))
+
+ ;; import fd_write again for grins.
+ (import "wasi_unstable" "fd_write" (func (type 0)))
+ (memory 1)
+ (data (i32.const 0) "duplicate import works!\0a")
+ (data (i32.const 64) "\00\00\00\00\18\00\00\00")
+
+ (func $_setup (type 1)
+ (call $write (i32.const 1) (i32.const 64) (i32.const 1) (i32.const 0)))
+
+ ;; declare that, actually, one of the imported functions is exported
+ (export "read_2" (func $read_2))
+ ;; and delcare that the *other* read function is also exported, by a
+ ;; different name. This lets us check that when we merge the functions,
+ ;; we also merge their export names properly.
+ (export "read" (func $read))
+
+ ;; and check that other exported functions still work, and are not affected
+ (export "write" (func $write))
+
+ ;; and that we can export local functions without issue
+ (export "_start" (func $_setup))
+)
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/exitcode.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/exitcode.c
new file mode 100644
index 0000000000..500d440ad0
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/exitcode.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 120;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/follow_symlink.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/follow_symlink.c
new file mode 100644
index 0000000000..e8db730df4
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/follow_symlink.c
@@ -0,0 +1,14 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/subdir2/input_link.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ assert(fputc(c, stdout) != EOF);
+ c = fgetc(file);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/fs.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/fs.c
new file mode 100644
index 0000000000..6f4bfa78e5
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/fs.c
@@ -0,0 +1,158 @@
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+
+int main(void)
+{
+ struct timespec times[2];
+ struct dirent * entry;
+ char buf[4];
+ DIR * dir;
+ FILE * fp;
+ struct stat st;
+ off_t offset;
+ int fd;
+ int res;
+
+ fd = open("/sandbox/testfile", O_CREAT | O_RDWR, 0644);
+ assert(fd != -1);
+
+ res = posix_fallocate(fd, 0, 10000);
+ assert(res == 0);
+
+ res = fstat(fd, &st);
+ assert(res == 0);
+ assert(st.st_size == 10000);
+
+ res = ftruncate(fd, 1000);
+ res = fstat(fd, &st);
+ assert(res == 0);
+ assert(st.st_size == 1000);
+ assert(st.st_nlink == 1);
+ res = posix_fadvise(fd, 0, 1000, POSIX_FADV_RANDOM);
+ assert(res == 0);
+
+ res = (int) write(fd, "test", 4);
+ assert(res == 4);
+
+ offset = lseek(fd, 0, SEEK_CUR);
+ assert(offset == 4);
+ offset = lseek(fd, 0, SEEK_END);
+ assert(offset == 1000);
+ offset = lseek(fd, 0, SEEK_SET);
+ assert(offset == 0);
+
+ res = fdatasync(fd);
+ assert(res == 0);
+
+ res = fsync(fd);
+ assert(res == 0);
+
+ times[0] = (struct timespec){ .tv_sec = 1557403800, .tv_nsec = 0 };
+ times[1] = (struct timespec){ .tv_sec = 1557403800, .tv_nsec = 0 };
+
+ res = futimens(fd, times);
+ assert(res == 0);
+
+ res = pread(fd, buf, sizeof buf, 2);
+ assert(res == 4);
+ assert(buf[1] == 't');
+
+ res = pwrite(fd, "T", 1, 3);
+ assert(res == 1);
+
+ res = pread(fd, buf, sizeof buf, 2);
+ assert(res == 4);
+ assert(buf[1] == 'T');
+
+ res = close(fd);
+ assert(res == 0);
+
+ dir = opendir("/nonexistent");
+ assert(dir == NULL);
+
+ res = mkdir("/sandbox/test", 0755);
+ assert(res == 0);
+
+ res = mkdir("/sandbox/test", 0755);
+ assert(res == -1);
+ assert(errno == EEXIST);
+
+ res = rmdir("/sandbox/test");
+ assert(res == 0);
+
+ res = rmdir("/sandbox/test");
+ assert(res == -1);
+
+ res = rename("/sandbox/testfile", "/sandbox/testfile2");
+ assert(res == 0);
+
+ res = unlink("/sandbox/testfile");
+ assert(res == -1);
+
+ res = access("/sandbox/testfile2", R_OK);
+ assert(res == 0);
+
+ res = link("/sandbox/testfile2", "/sandbox/testfile-link");
+ assert(res == 0);
+
+ res = access("/sandbox/testfile-link", R_OK);
+ assert(res == 0);
+
+ res = symlink("/sandbox/testfile-link", "/sandbox/testfile-symlink");
+ assert(res == 0);
+
+ res = symlink("/sandbox/testfile2", "/sandbox/testfile-symlink");
+ assert(res == -1);
+
+ res = sched_yield();
+ assert(res == 0);
+
+ fd = open("/sandbox/testfile2", O_RDONLY);
+ assert(fd != -1);
+
+ fp = fdopen(fd, "r");
+ assert(fp != NULL);
+
+ res = fgetc(fp);
+ assert(res == 't');
+
+ res = fclose(fp);
+ assert(res == 0);
+
+ dir = opendir("/sandbox");
+ assert(dir != NULL);
+
+ res = 0;
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_name[0] == '.') {
+ res += 1000;
+ } else {
+ res++;
+ }
+ }
+ assert(res == 2003);
+
+ res = closedir(dir);
+ assert(res == 0);
+
+ res = mkdir("/sandbox/a", 0755);
+ assert(res == 0);
+ res = mkdir("/sandbox/a/b", 0755);
+ assert(res == 0);
+ res = mkdir("/sandbox/a/b/c", 0755);
+ assert(res == 0);
+ res = access("/sandbox/a/b/c", R_OK);
+ assert(res == 0);
+
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getentropy.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getentropy.c
new file mode 100644
index 0000000000..439512df10
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getentropy.c
@@ -0,0 +1,17 @@
+#include <assert.h>
+#include <unistd.h>
+
+int main()
+{
+ char buf[256] = { 0 };
+ assert(getentropy(buf, 256) == 0);
+
+ for (int i = 0; i < 256; i++) {
+ if (buf[i] != 0) {
+ return 0;
+ }
+ }
+
+ // if this ever is reached, we either have a bug or should buy a lottery ticket
+ return 1;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getrusage.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getrusage.c
new file mode 100644
index 0000000000..7ff12fe12a
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getrusage.c
@@ -0,0 +1,30 @@
+#include <assert.h>
+#include <sys/resource.h>
+
+// Temporary fix until
+// https://github.com/CraneStation/wasi-sysroot/pull/24/
+// is available in wasi-sdk package
+extern int getrusage(int who, struct rusage *usage);
+
+int main()
+{
+ struct rusage ru1;
+ getrusage(RUSAGE_SELF, &ru1);
+
+ for (int i = 0; i < 1000; i++) {
+ }
+
+ struct rusage ru2;
+ getrusage(RUSAGE_SELF, &ru2);
+
+ // assert that some time has passed
+ long long s1 = ru1.ru_utime.tv_sec;
+ long long us1 = ru1.ru_utime.tv_usec;
+ long long s2 = ru2.ru_utime.tv_sec;
+ long long us2 = ru2.ru_utime.tv_usec;
+ assert(s1 <= s2);
+ if (s1 == s2) {
+ // strictly less than, so the timestamps can't be equal
+ assert(us1 < us2);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/gettimeofday.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/gettimeofday.c
new file mode 100644
index 0000000000..f9e8d5a811
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/gettimeofday.c
@@ -0,0 +1,26 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+int main()
+{
+ struct timeval tv1;
+ gettimeofday(&tv1, NULL);
+
+ for (int i = 0; i < 1000; i++) {
+ }
+
+ struct timeval tv2;
+ gettimeofday(&tv2, NULL);
+
+ // assert that some time has passed
+ long long s1 = tv1.tv_sec;
+ long long us1 = tv1.tv_usec;
+ long long s2 = tv2.tv_sec;
+ long long us2 = tv2.tv_usec;
+ assert(s1 <= s2);
+ if (s1 == s2) {
+ // strictly less than, so the timestamps can't be equal
+ assert(us1 < us2);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/notdir.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/notdir.c
new file mode 100644
index 0000000000..fcd47a69db
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/notdir.c
@@ -0,0 +1,12 @@
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+
+int main()
+{
+ DIR *dir = opendir("/sandbox/notadir");
+ assert(dir == NULL);
+ assert(errno == ENOTDIR);
+
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/poll.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/poll.c
new file mode 100644
index 0000000000..d8f9a8c1de
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/poll.c
@@ -0,0 +1,32 @@
+#include <assert.h>
+#include <poll.h>
+#include <time.h>
+#include <unistd.h>
+
+int main(void)
+{
+ struct pollfd fds[2];
+ time_t before, now;
+ int ret;
+
+ fds[0] = (struct pollfd){ .fd = 1, .events = POLLOUT, .revents = 0 };
+ fds[1] = (struct pollfd){ .fd = 2, .events = POLLOUT, .revents = 0 };
+
+ ret = poll(fds, 2, -1);
+ assert(ret == 2);
+ assert(fds[0].revents == POLLOUT);
+ assert(fds[1].revents == POLLOUT);
+
+ fds[0] = (struct pollfd){ .fd = 0, .events = POLLIN, .revents = 0 };
+ time(&before);
+ ret = poll(fds, 1, 2000);
+ time(&now);
+ assert(ret == 0);
+ assert(now - before >= 2);
+
+ sleep(1);
+ time(&now);
+ assert(now - before >= 3);
+
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/preopen_populates.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/preopen_populates.c
new file mode 100644
index 0000000000..58fe69254d
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/preopen_populates.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file.c
new file mode 100644
index 0000000000..cdd758158e
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file.c
@@ -0,0 +1,14 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/input.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ assert(fputc(c, stdout) != EOF);
+ c = fgetc(file);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file_twice.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file_twice.c
new file mode 100644
index 0000000000..c2504fb40e
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file_twice.c
@@ -0,0 +1,16 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main()
+{
+ for (int i = 0; i < 2; i++) {
+ FILE *file = fopen("/sandbox/input.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ assert(fputc(c, stdout) != EOF);
+ c = fgetc(file);
+ }
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stat.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stat.c
new file mode 100644
index 0000000000..7974c31d84
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stat.c
@@ -0,0 +1,54 @@
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#define BASE_DIR "/sandbox"
+#define OUTPUT_DIR BASE_DIR "/testdir"
+#define PATH OUTPUT_DIR "/output.txt"
+#define SIZE 500
+
+int main(void)
+{
+ struct stat st;
+ int fd;
+ int ret;
+ off_t pos;
+
+ (void) st;
+ ret = mkdir(OUTPUT_DIR, 0755);
+ assert(ret == 0);
+
+ fd = open(PATH, O_CREAT | O_WRONLY, 0666);
+ assert(fd != -1);
+
+ pos = lseek(fd, SIZE - 1, SEEK_SET);
+ assert(pos == SIZE - 1);
+
+ ret = (int) write(fd, "", 1);
+ assert(ret == 1);
+
+ ret = fstat(fd, &st);
+ assert(ret == 0);
+ assert(st.st_size == SIZE);
+
+ ret = close(fd);
+ assert(ret == 0);
+
+ ret = access(PATH, R_OK);
+ assert(ret == 0);
+
+ ret = stat(PATH, &st);
+ assert(ret == 0);
+ assert(st.st_size == SIZE);
+
+ ret = unlink(PATH);
+ assert(ret == 0);
+
+ ret = stat(PATH, &st);
+ assert(ret == -1);
+
+ return 0;
+} \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stdin.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stdin.c
new file mode 100644
index 0000000000..137a447602
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stdin.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main(void)
+{
+ char x[32];
+
+ fgets(x, sizeof x, stdin);
+ fputs(x, stdout);
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_escape.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_escape.c
new file mode 100644
index 0000000000..20929d5193
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_escape.c
@@ -0,0 +1,10 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/subdir/outside.txt", "r");
+ assert(file == NULL);
+ assert(errno == ENOTCAPABLE);
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_loop.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_loop.c
new file mode 100644
index 0000000000..7256121c3b
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_loop.c
@@ -0,0 +1,10 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/subdir1/loop1", "r");
+ assert(file == NULL);
+ assert(errno == ELOOP);
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/write_file.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/write_file.c
new file mode 100644
index 0000000000..5922c02763
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/write_file.c
@@ -0,0 +1,16 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+static char *message = "hello, file!";
+
+int main()
+{
+ FILE *file = fopen("/sandbox/output.txt", "w");
+ assert(file != NULL);
+
+ int nwritten = fprintf(file, "%s", message);
+ assert(nwritten == strlen(message));
+
+ assert(fclose(file) == 0);
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/test_helpers/mod.rs b/third_party/rust/lucet-wasi-wasmsbx/tests/test_helpers/mod.rs
new file mode 100644
index 0000000000..455928a92b
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/test_helpers/mod.rs
@@ -0,0 +1,127 @@
+use failure::{bail, Error};
+use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region};
+use lucet_wasi::host::__wasi_exitcode_t;
+use lucet_wasi::{self, WasiCtx, WasiCtxBuilder};
+use lucet_wasi_sdk::{CompileOpts, Link};
+use lucetc::{Lucetc, LucetcOpts};
+use std::fs::File;
+use std::io::Read;
+use std::os::unix::io::{FromRawFd, IntoRawFd};
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
+use tempfile::TempDir;
+
+pub const LUCET_WASI_ROOT: &'static str = env!("CARGO_MANIFEST_DIR");
+
+pub fn test_module_wasi<P: AsRef<Path>>(cfile: P) -> Result<Arc<dyn Module>, Error> {
+ let c_path = guest_file(&cfile);
+ wasi_test(c_path)
+}
+
+pub fn guest_file<P: AsRef<Path>>(path: P) -> PathBuf {
+ let p = if path.as_ref().is_absolute() {
+ path.as_ref().to_owned()
+ } else {
+ Path::new(LUCET_WASI_ROOT)
+ .join("tests")
+ .join("guests")
+ .join(path)
+ };
+ assert!(p.exists(), "test case source file {} exists", p.display());
+ p
+}
+
+pub fn wasi_test<P: AsRef<Path>>(file: P) -> Result<Arc<dyn Module>, Error> {
+ let workdir = TempDir::new().expect("create working directory");
+
+ let wasm_path = match file.as_ref().extension().and_then(|x| x.to_str()) {
+ Some("c") => {
+ // some tests are .c, and must be compiled/linked to .wasm we can run
+ let wasm_build = Link::new(&[file])
+ .with_cflag("-Wall")
+ .with_cflag("-Werror")
+ .with_print_output(true);
+
+ let wasm_file = workdir.path().join("out.wasm");
+ wasm_build.link(wasm_file.clone())?;
+
+ wasm_file
+ }
+ Some("wasm") | Some("wat") => {
+ // others are just wasm we can run directly
+ file.as_ref().to_owned()
+ }
+ Some(ext) => {
+ panic!("unknown test file extension: .{}", ext);
+ }
+ None => {
+ panic!("unknown test file, has no extension");
+ }
+ };
+
+ wasi_load(&workdir, wasm_path)
+}
+
+pub fn wasi_load<P: AsRef<Path>>(
+ workdir: &TempDir,
+ wasm_file: P,
+) -> Result<Arc<dyn Module>, Error> {
+ let native_build = Lucetc::new(wasm_file).with_bindings(lucet_wasi::bindings());
+
+ let so_file = workdir.path().join("out.so");
+
+ native_build.shared_object_file(so_file.clone())?;
+
+ let dlmodule = DlModule::load(so_file)?;
+
+ Ok(dlmodule as Arc<dyn Module>)
+}
+
+pub fn run<P: AsRef<Path>>(path: P, ctx: WasiCtx) -> Result<__wasi_exitcode_t, Error> {
+ let region = MmapRegion::create(1, &Limits::default())?;
+ let module = test_module_wasi(path)?;
+
+ let mut inst = region
+ .new_instance_builder(module)
+ .with_embed_ctx(ctx)
+ .build()?;
+
+ match inst.run("_start", &[]) {
+ // normal termination implies 0 exit code
+ Ok(_) => Ok(0),
+ Err(lucet_runtime::Error::RuntimeTerminated(
+ lucet_runtime::TerminationDetails::Provided(any),
+ )) => Ok(*any
+ .downcast_ref::<__wasi_exitcode_t>()
+ .expect("termination yields an exitcode")),
+ Err(e) => bail!("runtime error: {}", e),
+ }
+}
+
+pub fn run_with_stdout<P: AsRef<Path>>(
+ path: P,
+ ctx: WasiCtxBuilder,
+) -> Result<(__wasi_exitcode_t, String), Error> {
+ let (pipe_out, pipe_in) = nix::unistd::pipe()?;
+
+ let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?;
+
+ let exitcode = run(path, ctx)?;
+
+ let mut stdout_file = unsafe { File::from_raw_fd(pipe_out) };
+ let mut stdout = String::new();
+ stdout_file.read_to_string(&mut stdout)?;
+ nix::unistd::close(stdout_file.into_raw_fd())?;
+
+ Ok((exitcode, stdout))
+}
+
+/// Call this if you're having trouble with `__wasi_*` symbols not being exported.
+///
+/// This is pretty hackish; we will hopefully be able to avoid this altogether once [this
+/// issue](https://github.com/rust-lang/rust/issues/58037) is addressed.
+#[no_mangle]
+#[doc(hidden)]
+pub extern "C" fn lucet_wasi_tests_internal_ensure_linked() {
+ lucet_wasi::hostcalls::ensure_linked();
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/tests.rs b/third_party/rust/lucet-wasi-wasmsbx/tests/tests.rs
new file mode 100644
index 0000000000..18cdf386d2
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/tests.rs
@@ -0,0 +1,405 @@
+mod test_helpers;
+
+use crate::test_helpers::{run, run_with_stdout, LUCET_WASI_ROOT};
+use lucet_wasi::{WasiCtx, WasiCtxBuilder};
+use std::fs::File;
+use std::path::Path;
+use tempfile::TempDir;
+
+#[test]
+fn double_import() {
+ let ctx = WasiCtxBuilder::new();
+
+ let (exitcode, stdout) = run_with_stdout("duplicate_import.wat", ctx).unwrap();
+
+ assert_eq!(stdout, "duplicate import works!\n");
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn hello() {
+ let ctx = WasiCtxBuilder::new().args(&["hello"]);
+
+ let (exitcode, stdout) = run_with_stdout(
+ Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
+ ctx,
+ )
+ .unwrap();
+
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, "hello, wasi!\n");
+}
+
+#[test]
+fn hello_args() {
+ let ctx = WasiCtxBuilder::new().args(&["hello", "test suite"]);
+
+ let (exitcode, stdout) = run_with_stdout(
+ Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
+ ctx,
+ )
+ .unwrap();
+
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, "hello, test suite!\n");
+}
+
+#[test]
+fn hello_env() {
+ let ctx = WasiCtxBuilder::new()
+ .args(&["hello", "test suite"])
+ .env("GREETING", "goodbye");
+
+ let (exitcode, stdout) = run_with_stdout(
+ Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
+ ctx,
+ )
+ .unwrap();
+
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, "goodbye, test suite!\n");
+}
+
+#[test]
+fn exitcode() {
+ let ctx = WasiCtx::new(&["exitcode"]);
+
+ let exitcode = run("exitcode.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 120);
+}
+
+#[test]
+fn clock_getres() {
+ let ctx = WasiCtx::new(&["clock_getres"]);
+
+ let exitcode = run("clock_getres.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn getrusage() {
+ let ctx = WasiCtx::new(&["getrusage"]);
+
+ let exitcode = run("getrusage.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn gettimeofday() {
+ let ctx = WasiCtx::new(&["gettimeofday"]);
+
+ let exitcode = run("gettimeofday.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn getentropy() {
+ let ctx = WasiCtx::new(&["getentropy"]);
+
+ let exitcode = run("getentropy.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn stdin() {
+ use std::io::Write;
+ use std::os::unix::io::FromRawFd;
+
+ let (pipe_out, pipe_in) = nix::unistd::pipe().expect("can create pipe");
+
+ let mut stdin_file = unsafe { File::from_raw_fd(pipe_in) };
+ write!(stdin_file, "hello from stdin!").expect("pipe write succeeds");
+ drop(stdin_file);
+
+ let ctx = unsafe { WasiCtxBuilder::new().args(&["stdin"]).raw_fd(0, pipe_out) };
+
+ let (exitcode, stdout) = run_with_stdout("stdin.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, "hello from stdin!");
+}
+
+#[test]
+fn preopen_populates() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+ let preopen_dir = File::open(preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["preopen_populates"])
+ .preopened_dir(preopen_dir, "/preopen")
+ .build()
+ .expect("can build WasiCtx");
+
+ let exitcode = run("preopen_populates.c", ctx).unwrap();
+
+ drop(tmpdir);
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn write_file() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["write_file"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .expect("can build WasiCtx");
+
+ let exitcode = run("write_file.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ let output = std::fs::read(preopen_host_path.join("output.txt")).unwrap();
+
+ assert_eq!(output.as_slice(), b"hello, file!");
+
+ drop(tmpdir);
+}
+
+#[test]
+fn read_file() {
+ const MESSAGE: &'static str = "hello from file!";
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+
+ std::fs::write(preopen_host_path.join("input.txt"), MESSAGE).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["read_file"])
+ .preopened_dir(preopen_dir, "/sandbox");
+
+ let (exitcode, stdout) = run_with_stdout("read_file.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ assert_eq!(&stdout, MESSAGE);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn read_file_twice() {
+ const MESSAGE: &'static str = "hello from file!";
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+
+ std::fs::write(preopen_host_path.join("input.txt"), MESSAGE).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["read_file_twice"])
+ .preopened_dir(preopen_dir, "/sandbox");
+
+ let (exitcode, stdout) = run_with_stdout("read_file_twice.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ let double_message = format!("{}{}", MESSAGE, MESSAGE);
+ assert_eq!(stdout, double_message);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn cant_dotdot() {
+ const MESSAGE: &'static str = "hello from file!";
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+
+ std::fs::write(
+ preopen_host_path.parent().unwrap().join("outside.txt"),
+ MESSAGE,
+ )
+ .unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["cant_dotdot"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .unwrap();
+
+ let exitcode = run("cant_dotdot.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ drop(tmpdir);
+}
+
+#[ignore] // needs fd_readdir
+#[test]
+fn notdir() {
+ const MESSAGE: &'static str = "hello from file!";
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+
+ std::fs::write(preopen_host_path.join("notadir"), MESSAGE).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["notdir"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .unwrap();
+
+ let exitcode = run("notdir.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn follow_symlink() {
+ const MESSAGE: &'static str = "hello from file!";
+
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ let subdir1 = preopen_host_path.join("subdir1");
+ let subdir2 = preopen_host_path.join("subdir2");
+ std::fs::create_dir_all(&subdir1).unwrap();
+ std::fs::create_dir_all(&subdir2).unwrap();
+
+ std::fs::write(subdir1.join("input.txt"), MESSAGE).unwrap();
+
+ std::os::unix::fs::symlink("../subdir1/input.txt", subdir2.join("input_link.txt")).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["follow_symlink"])
+ .preopened_dir(preopen_dir, "/sandbox");
+
+ let (exitcode, stdout) = run_with_stdout("follow_symlink.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, MESSAGE);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn symlink_loop() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ let subdir1 = preopen_host_path.join("subdir1");
+ let subdir2 = preopen_host_path.join("subdir2");
+ std::fs::create_dir_all(&subdir1).unwrap();
+ std::fs::create_dir_all(&subdir2).unwrap();
+
+ std::os::unix::fs::symlink("../subdir1/loop1", subdir2.join("loop2")).unwrap();
+ std::os::unix::fs::symlink("../subdir2/loop2", subdir1.join("loop1")).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["symlink_loop"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .unwrap();
+
+ let exitcode = run("symlink_loop.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn symlink_escape() {
+ const MESSAGE: &'static str = "hello from file!";
+
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ let subdir = preopen_host_path.join("subdir");
+ std::fs::create_dir_all(&subdir).unwrap();
+
+ std::fs::write(
+ preopen_host_path.parent().unwrap().join("outside.txt"),
+ MESSAGE,
+ )
+ .unwrap();
+ std::os::unix::fs::symlink("../../outside.txt", subdir.join("outside.txt")).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["symlink_escape"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .unwrap();
+
+ let exitcode = run("symlink_escape.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn pseudoquine() {
+ let examples_dir = Path::new(LUCET_WASI_ROOT).join("examples");
+ let pseudoquine_c = examples_dir.join("pseudoquine.c");
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["pseudoquine"])
+ .preopened_dir(File::open(examples_dir).unwrap(), "/examples");
+
+ let (exitcode, stdout) = run_with_stdout(&pseudoquine_c, ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+
+ let expected = std::fs::read_to_string(&pseudoquine_c).unwrap();
+
+ assert_eq!(stdout, expected);
+}
+
+#[test]
+fn poll() {
+ let ctx = WasiCtxBuilder::new().args(&["poll"]).build().unwrap();
+ let exitcode = run("poll.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn stat() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+ let ctx = WasiCtxBuilder::new()
+ .args(&["stat"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .expect("can build WasiCtx");
+ let exitcode = run("stat.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn fs() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+ let ctx = WasiCtxBuilder::new()
+ .args(&["stat"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .expect("can build WasiCtx");
+ let exitcode = run("fs.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+}