diff options
-rw-r--r-- | src/shared/printf.c | 3 | ||||
-rw-r--r-- | src/user/app/tests/kernel/fs.c | 34 | ||||
-rw-r--r-- | src/user/app/tests/kernel/misc.c | 65 | ||||
-rw-r--r-- | src/user/app/tests/kernel/miscsyscall.c | 264 | ||||
-rw-r--r-- | src/user/app/tests/libc/esemaphore.c (renamed from src/user/app/tests/semaphore.c) | 19 | ||||
-rw-r--r-- | src/user/app/tests/libc/string.c | 25 | ||||
-rw-r--r-- | src/user/app/tests/pipe.c | 117 | ||||
-rw-r--r-- | src/user/app/tests/printf.c | 27 | ||||
-rw-r--r-- | src/user/app/tests/stress.c | 1 | ||||
-rw-r--r-- | src/user/app/tests/tests.c | 307 | ||||
-rw-r--r-- | src/user/app/tests/tests.h | 18 |
11 files changed, 433 insertions, 447 deletions
diff --git a/src/shared/printf.c b/src/shared/printf.c index f019ac4..4e81603 100644 --- a/src/shared/printf.c +++ b/src/shared/printf.c @@ -47,8 +47,7 @@ static void pad(struct out_state *os, struct mods *m, size_t len) { } static void output_uint(struct out_state *os, struct mods *m, unsigned long long n) { - // TODO static assert sizeof(unsigned long long) <= 8 - char buf[20]; + char buf[sizeof(unsigned long long) * 3]; size_t pos = sizeof(buf); if (!n) { diff --git a/src/user/app/tests/kernel/fs.c b/src/user/app/tests/kernel/fs.c new file mode 100644 index 0000000..c8d2eae --- /dev/null +++ b/src/user/app/tests/kernel/fs.c @@ -0,0 +1,34 @@ +#include "../tests.h" +#include <camellia/syscalls.h> + +static void test_unfinished_req(void) { + handle_t h; + if (_syscall_fork(FORK_NEWFS, &h)) { + // TODO make a similar test with all 0s passed to fs_wait + struct fs_wait_response res; + _syscall_fs_wait(NULL, 0, &res); + // TODO second fs_wait + exit(0); + } else { + _syscall_mount(h, "/", 1); + int ret = _syscall_open("/", 1, 0); + test(ret < 0); + // the handler quits while handling that call - but this syscall should return anyways + } +} + +static void test_orphaned_fs(void) { + handle_t h; + if (_syscall_fork(FORK_NEWFS, &h)) { + exit(0); + } else { + _syscall_mount(h, "/", 1); + int ret = _syscall_open("/", 1, 0); + test(ret < 0); + } +} + +void r_k_fs(void) { + run_test(test_unfinished_req); + run_test(test_orphaned_fs); +} diff --git a/src/user/app/tests/kernel/misc.c b/src/user/app/tests/kernel/misc.c new file mode 100644 index 0000000..6899e18 --- /dev/null +++ b/src/user/app/tests/kernel/misc.c @@ -0,0 +1,65 @@ +#include "../tests.h" +#include <camellia/errno.h> +#include <camellia/syscalls.h> +#include <string.h> + +static void test_fault_kill(void) { + if (!fork()) { /* invalid memory access */ + asm volatile("movb $69, 0" ::: "memory"); + // TODO test_fail which works in children + printf("this shouldn't happen"); + exit(-1); + } + if (!fork()) { /* #GP */ + asm volatile("hlt" ::: "memory"); + printf("this shouldn't happen"); + exit(-1); + } + + int await_cnt = 0; + while (_syscall_await() != ~0) await_cnt++; + test(await_cnt == 2); +} + +static void test_efault(void) { + const char *str = "o, 16 characters"; + char str2[16]; + char *invalid = (void*)0x1000; + handle_t h; + + memcpy(str2, str, 16); + + test((h = _syscall_open(TMPFILEPATH, strlen(TMPFILEPATH), OPEN_CREATE))); + test(_syscall_write(h, str, 16, 0, 0) == 16); + test(_syscall_write(h, str2, 16, 0, 0) == 16); + + test(_syscall_write(h, invalid, 16, 0, 0) == -EFAULT); + + /* x64 non-canonical pointers */ + test(_syscall_write(h, (void*)((uintptr_t)str ^ 0x8000000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str ^ 0x1000000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str ^ 0x0100000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str ^ 0x0010000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str ^ 0x0001000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str ^ 0x0000800000000000), 16, 0, 0) == -EFAULT); + + test(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x8000000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x1000000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x0100000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x0010000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x0001000000000000), 16, 0, 0) == -EFAULT); + test(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x0000800000000000), 16, 0, 0) == -EFAULT); + + test(_syscall_write(h, str, 16, 0, 0) == 16); + close(h); +} + +static void test_invalid_syscall(void) { + test(_syscall(~0, 0, 0, 0, 0, 0) < 0); +} + +void r_k_misc(void) { + run_test(test_fault_kill); + run_test(test_efault); + run_test(test_invalid_syscall); +} diff --git a/src/user/app/tests/kernel/miscsyscall.c b/src/user/app/tests/kernel/miscsyscall.c new file mode 100644 index 0000000..22b6b33 --- /dev/null +++ b/src/user/app/tests/kernel/miscsyscall.c @@ -0,0 +1,264 @@ +#include "../tests.h" +#include <camellia/errno.h> +#include <camellia/execbuf.h> +#include <camellia/flags.h> +#include <camellia/syscalls.h> +#include <string.h> +#include <unistd.h> + + +static void test_await(void) { + /* creates 16 child processes, each returning a different value. then checks + * if await() returns every value exactly once */ + int ret; + int counts[16] = {0}; + + for (int i = 0; i < 16; i++) + if (!fork()) + exit(i); + + while ((ret = _syscall_await()) != ~0) { + test(0 <= ret && ret < 16); + counts[ret]++; + } + + for (int i = 0; i < 16; i++) + test(counts[i] == 1); +} + +static void test_pipe(void) { + const char *pipe_msgs[2] = {"hello", "world"}; + handle_t ends[2]; + char buf[16]; + + /* test regular reads / writes */ + test(_syscall_pipe(ends, 0) >= 0); + if (!fork()) { + /* those repeated asserts ensure that you can't read/write to the wrong ends */ + test(_syscall_read(ends[1], buf, 16, 0) < 0); + test(_syscall_write(ends[0], buf, 16, 0, 0) < 0); + + test(5 == _syscall_write(ends[1], pipe_msgs[0], 5, -1, 0)); + + test(_syscall_read(ends[1], buf, 16, 0) < 0); + test(_syscall_write(ends[0], buf, 16, 0, 0) < 0); + + test(5 == _syscall_write(ends[1], pipe_msgs[1], 5, -1, 0)); + + exit(0); + } else { + test(_syscall_read(ends[1], buf, 16, 0) < 0); + test(_syscall_write(ends[0], buf, 16, 0, 0) < 0); + + test(5 == _syscall_read(ends[0], buf, 16, 0)); + test(!memcmp(buf, pipe_msgs[0], 5)); + + test(_syscall_read(ends[1], buf, 16, 0) < 0); + test(_syscall_write(ends[0], buf, 16, 0, 0) < 0); + + test(5 == _syscall_read(ends[0], buf, 16, 0)); + test(!memcmp(buf, pipe_msgs[1], 5)); + + _syscall_await(); + } + close(ends[0]); + close(ends[1]); + + + /* writing to pipes with one end closed */ + test(_syscall_pipe(ends, 0) >= 0); + for (int i = 0; i < 16; i++) { + if (!fork()) { + close(ends[1]); + test(_syscall_read(ends[0], buf, 16, 0) < 0); + exit(0); + } + } + close(ends[1]); + for (int i = 0; i < 16; i++) + _syscall_await(); + close(ends[0]); + + test(_syscall_pipe(ends, 0) >= 0); + for (int i = 0; i < 16; i++) { + if (!fork()) { + close(ends[0]); + test(_syscall_write(ends[1], buf, 16, 0, 0) < 0); + exit(0); + } + } + close(ends[0]); + for (int i = 0; i < 16; i++) + _syscall_await(); + close(ends[1]); + + + /* queueing */ + test(_syscall_pipe(ends, 0) >= 0); + for (int i = 0; i < 16; i++) { + if (!fork()) { + test(_syscall_write(ends[1], pipe_msgs[0], 5, -1, 0) == 5); + exit(0); + } + } + close(ends[1]); + for (int i = 0; i < 16; i++) { + test(_syscall_read(ends[0], buf, sizeof buf, 0) == 5); + _syscall_await(); + } + test(_syscall_read(ends[0], buf, sizeof buf, 0) < 0); + close(ends[0]); + + test(_syscall_pipe(ends, 0) >= 0); + for (int i = 0; i < 16; i++) { + if (!fork()) { + memset(buf, 0, sizeof buf); + test(_syscall_read(ends[0], buf, 5, -1) == 5); + test(!memcmp(buf, pipe_msgs[1], 5)); + exit(0); + } + } + close(ends[0]); + for (int i = 0; i < 16; i++) { + test(_syscall_write(ends[1], pipe_msgs[1], 5, -1, 0) == 5); + _syscall_await(); + } + test(_syscall_write(ends[1], pipe_msgs[1], 5, -1, 0) < 0); + close(ends[1]); + + + // not a to.do detect when all processes that can read are stuck on writing to the pipe and vice versa + // it seems like linux just lets the process hang endlessly. +} + +static void test_memflag(void) { + void *page = (void*)0x77777000; + _syscall_memflag(page, 4096, MEMFLAG_PRESENT); // allocate page + memset(page, 77, 4096); // write to it + _syscall_memflag(page, 4096, 0); // free it + + if (!fork()) { + memset(page, 11, 4096); // should segfault + exit(0); + } else { + test(_syscall_await() != 0); // test if the process crashed + } + + char *pages[4]; + for (size_t i = 0; i < 4; i++) { + pages[i] = _syscall_memflag(NULL, 4096, MEMFLAG_FINDFREE); + test(pages[i] == _syscall_memflag(NULL, 4096, MEMFLAG_FINDFREE | MEMFLAG_PRESENT)); + if (i > 0) test(pages[i] != pages[i-1]); + *pages[i] = 0x77; + } + + for (size_t i = 0; i < 4; i++) + _syscall_memflag(pages, 4096, MEMFLAG_PRESENT); +} + +static void test_dup(void) { + handle_t pipe[2]; + handle_t h1, h2; + test(_syscall_pipe(pipe, 0) >= 0); + + if (!fork()) { + close(pipe[0]); + + h1 = _syscall_dup(pipe[1], -1, 0); + test(h1 >= 0); + test(h1 != pipe[1]); + h2 = _syscall_dup(h1, -1, 0); + test(h2 >= 0); + test(h2 != pipe[1] && h2 != h1); + + _syscall_write(pipe[1], "og", 2, 0, 0); + _syscall_write(h1, "h1", 2, 0, 0); + _syscall_write(h2, "h2", 2, 0, 0); + + close(pipe[1]); + _syscall_write(h1, "h1", 2, 0, 0); + _syscall_write(h2, "h2", 2, 0, 0); + + test(_syscall_dup(h1, pipe[1], 0) == pipe[1]); + test(_syscall_dup(h2, pipe[1], 0) == pipe[1]); + test(_syscall_dup(h1, pipe[1], 0) == pipe[1]); + test(_syscall_dup(h2, pipe[1], 0) == pipe[1]); + close(h1); + close(h2); + + test(_syscall_dup(pipe[1], h2, 0) == h2); + _syscall_write(h2, "h2", 2, 0, 0); + close(h2); + + test(_syscall_dup(pipe[1], h1, 0) == h1); + _syscall_write(h1, "h1", 2, 0, 0); + close(h1); + + exit(0); + } else { + char buf[16]; + size_t count = 0; + close(pipe[1]); + while (_syscall_read(pipe[0], buf, sizeof buf, 0) >= 0) + count++; + test(count == 7); + _syscall_await(); + } + + + close(pipe[0]); +} + +static void test_execbuf(void) { + // not really a test, TODO + // also TODO check returning last syscall value + const char str1[] = "test_execbuf: string 1\n"; + const char str2[] = "test_execbuf: and 2\n"; + uint64_t buf[] = { + EXECBUF_SYSCALL, _SYSCALL_WRITE, 1, (uintptr_t)str1, sizeof(str1) - 1, -1, 0, + EXECBUF_SYSCALL, _SYSCALL_WRITE, 1, (uintptr_t)str2, sizeof(str2) - 1, -1, 0, + EXECBUF_SYSCALL, _SYSCALL_EXIT, 0, 0, 0, 0, 0, + }; + _syscall_execbuf(buf, sizeof buf); + test_fail(); +} + +static void test_sleep(void) { + // TODO yet another of those fake tests that you have to verify by hand + if (!fork()) { + if (!fork()) { + _syscall_sleep(100); + printf("1\n"); + _syscall_sleep(200); + printf("3\n"); + _syscall_sleep(200); + printf("5\n"); + _syscall_exit(0); + } + if (!fork()) { + printf("0\n"); + _syscall_sleep(200); + printf("2\n"); + _syscall_sleep(200); + printf("4\n"); + /* get killed while asleep + * a peaceful death, i suppose. */ + for (;;) _syscall_sleep(1000000000); + } + _syscall_await(); + _syscall_exit(0); + } + + /* this part checks if, after killing an asleep process, other processes can still wake up */ + _syscall_sleep(600); + printf("6\n"); +} + +void r_k_miscsyscall(void) { + run_test(test_await); + run_test(test_pipe); + run_test(test_memflag); + run_test(test_dup); + run_test(test_execbuf); + run_test(test_sleep); +} diff --git a/src/user/app/tests/semaphore.c b/src/user/app/tests/libc/esemaphore.c index 956734e..c78dd56 100644 --- a/src/user/app/tests/semaphore.c +++ b/src/user/app/tests/libc/esemaphore.c @@ -1,5 +1,4 @@ -#define TEST_MACROS -#include "tests.h" +#include "../tests.h" #include <camellia/flags.h> #include <camellia/syscalls.h> #include <stdio.h> @@ -34,21 +33,21 @@ static void even(handle_t out, struct evil_sem *sem1, struct evil_sem *sem2) { esem_signal(sem2); } -void test_semaphore(void) { +static void test_semaphore(void) { struct evil_sem *sem1, *sem2; handle_t pipe[2]; - assert(_syscall_pipe(pipe, 0) >= 0); + test(_syscall_pipe(pipe, 0) >= 0); if (!fork()) { sem1 = esem_new(0); sem2 = esem_new(0); - assert(sem1 && sem2); + test(sem1 && sem2); if (!fork()) { odd(pipe[1], sem1, sem2); exit(69); } else { even(pipe[1], sem1, sem2); - assert(_syscall_await() == 69); + test(_syscall_await() == 69); } esem_free(sem1); esem_free(sem2); @@ -57,13 +56,13 @@ void test_semaphore(void) { sem1 = esem_new(0); sem2 = esem_new(0); - assert(sem1 && sem2); + test(sem1 && sem2); if (!fork()) { even(pipe[1], sem1, sem2); exit(69); } else { odd(pipe[1], sem1, sem2); - assert(_syscall_await() == 69); + test(_syscall_await() == 69); _syscall_await(); } esem_free(sem1); @@ -89,3 +88,7 @@ void test_semaphore(void) { _syscall_await(); } } + +void r_libc_esemaphore(void) { + run_test(test_semaphore); +} diff --git a/src/user/app/tests/libc/string.c b/src/user/app/tests/libc/string.c new file mode 100644 index 0000000..8f889dc --- /dev/null +++ b/src/user/app/tests/libc/string.c @@ -0,0 +1,25 @@ +#include "../tests.h" +#include <string.h> + +static void test_strtol(void) { + char *end; + test(1234 == strtol("1234", NULL, 10)); + test(1234 == strtol("+1234", NULL, 10)); + test(-1234 == strtol("-1234", NULL, 10)); + + test(1234 == strtol("1234", &end, 10)); + test(!strcmp("", end)); + test(1234 == strtol(" 1234hello", &end, 10)); + test(!strcmp("hello", end)); + + test(1234 == strtol(" 1234hello", &end, 0)); + test(!strcmp("hello", end)); + test(0xCAF3 == strtol(" 0xCaF3hello", &end, 0)); + test(!strcmp("hello", end)); + test(01234 == strtol(" 01234hello", &end, 0)); + test(!strcmp("hello", end)); +} + +void r_libc_string(void) { + run_test(test_strtol); +} diff --git a/src/user/app/tests/pipe.c b/src/user/app/tests/pipe.c deleted file mode 100644 index 2d67fa7..0000000 --- a/src/user/app/tests/pipe.c +++ /dev/null @@ -1,117 +0,0 @@ -#define TEST_MACROS -#include "tests.h" -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <string.h> -#include <unistd.h> - -static const char *pipe_msgs[2] = {"hello", "world"}; - -void test_pipe(void) { - handle_t ends[2]; - char buf[16]; - int ret; - - /* test regular reads / writes */ - assert(_syscall_pipe(ends, 0) >= 0); - if (!fork()) { - /* those repeated asserts ensure that you can't read/write to the wrong ends */ - assert(_syscall_read(ends[1], buf, 16, 0) < 0); - assert(_syscall_write(ends[0], buf, 16, 0, 0) < 0); - - ret = _syscall_write(ends[1], pipe_msgs[0], 5, -1, 0); - assert(ret == 5); - - assert(_syscall_read(ends[1], buf, 16, 0) < 0); - assert(_syscall_write(ends[0], buf, 16, 0, 0) < 0); - - ret = _syscall_write(ends[1], pipe_msgs[1], 5, -1, 0); - assert(ret == 5); - - exit(0); - } else { - assert(_syscall_read(ends[1], buf, 16, 0) < 0); - assert(_syscall_write(ends[0], buf, 16, 0, 0) < 0); - - ret = _syscall_read(ends[0], buf, 16, 0); - assert(ret == 5); - assert(!memcmp(buf, pipe_msgs[0], 5)); - - assert(_syscall_read(ends[1], buf, 16, 0) < 0); - assert(_syscall_write(ends[0], buf, 16, 0, 0) < 0); - - _syscall_read(ends[0], buf, 16, 0); - assert(ret == 5); - assert(!memcmp(buf, pipe_msgs[1], 5)); - - _syscall_await(); - } - close(ends[0]); - close(ends[1]); - - - /* writing to pipes with one end closed */ - assert(_syscall_pipe(ends, 0) >= 0); - for (int i = 0; i < 16; i++) { - if (!fork()) { - close(ends[1]); - assert(_syscall_read(ends[0], buf, 16, 0) < 0); - exit(0); - } - } - close(ends[1]); - for (int i = 0; i < 16; i++) - _syscall_await(); - close(ends[0]); - - assert(_syscall_pipe(ends, 0) >= 0); - for (int i = 0; i < 16; i++) { - if (!fork()) { - close(ends[0]); - assert(_syscall_write(ends[1], buf, 16, 0, 0) < 0); - exit(0); - } - } - close(ends[0]); - for (int i = 0; i < 16; i++) - _syscall_await(); - close(ends[1]); - - - /* queueing */ - assert(_syscall_pipe(ends, 0) >= 0); - for (int i = 0; i < 16; i++) { - if (!fork()) { - assert(_syscall_write(ends[1], pipe_msgs[0], 5, -1, 0) == 5); - exit(0); - } - } - close(ends[1]); - for (int i = 0; i < 16; i++) { - assert(_syscall_read(ends[0], buf, sizeof buf, 0) == 5); - _syscall_await(); - } - assert(_syscall_read(ends[0], buf, sizeof buf, 0) < 0); - close(ends[0]); - - assert(_syscall_pipe(ends, 0) >= 0); - for (int i = 0; i < 16; i++) { - if (!fork()) { - memset(buf, 0, sizeof buf); - assert(_syscall_read(ends[0], buf, 5, -1) == 5); - assert(!memcmp(buf, pipe_msgs[1], 5)); - exit(0); - } - } - close(ends[0]); - for (int i = 0; i < 16; i++) { - assert(_syscall_write(ends[1], pipe_msgs[1], 5, -1, 0) == 5); - _syscall_await(); - } - assert(_syscall_write(ends[1], pipe_msgs[1], 5, -1, 0) < 0); - close(ends[1]); - - - // not a to.do detect when all processes that can read are stuck on writing to the pipe and vice versa - // it seems like linux just lets the process hang endlessly. -} diff --git a/src/user/app/tests/printf.c b/src/user/app/tests/printf.c index 6c6c609..4dc45bb 100644 --- a/src/user/app/tests/printf.c +++ b/src/user/app/tests/printf.c @@ -1,32 +1,35 @@ -#define TEST_MACROS #include "tests.h" #include <stdio.h> #include <string.h> -void test_printf(void) { +static void test_printf(void) { char buf[64]; memset(buf, '?', 64); /* test proper overflow handling in snprintf */ - assert(13 == snprintf(buf, 15, "That's 0x%x", 0x1337)); - assert(!memcmp(buf, "That's 0x1337\0??", 16)); - assert(17 == snprintf(buf, 15, "%05x %05x %05x", 0, 0, 0)); - assert(!memcmp(buf, "00000 00000 00\0?", 16)); + test(13 == snprintf(buf, 15, "That's 0x%x", 0x1337)); + test(!memcmp(buf, "That's 0x1337\0??", 16)); + test(17 == snprintf(buf, 15, "%05x %05x %05x", 0, 0, 0)); + test(!memcmp(buf, "00000 00000 00\0?", 16)); /* all the other stuff */ snprintf(buf, sizeof buf, "%010x", 0x1BABE); - assert(!strcmp(buf, "000001babe")); + test(!strcmp(buf, "000001babe")); snprintf(buf, sizeof buf, "%10x", 0x1BABE); - assert(!strcmp(buf, " 1babe")); + test(!strcmp(buf, " 1babe")); snprintf(buf, sizeof buf, "%10s", "hello"); - assert(!strcmp(buf, " hello")); + test(!strcmp(buf, " hello")); snprintf(buf, sizeof buf, "%s%%%s", "ab", "cd"); - assert(!strcmp(buf, "ab%cd")); + test(!strcmp(buf, "ab%cd")); snprintf(buf, sizeof buf, "%05u %05u", 1234, 56789); - assert(!strcmp(buf, "01234 56789")); + test(!strcmp(buf, "01234 56789")); snprintf(buf, sizeof buf, "%u %x", 0, 0); - assert(!strcmp(buf, "0 0")); + test(!strcmp(buf, "0 0")); +} + +void r_printf(void) { + run_test(test_printf); } diff --git a/src/user/app/tests/stress.c b/src/user/app/tests/stress.c index 9be88d7..9db752f 100644 --- a/src/user/app/tests/stress.c +++ b/src/user/app/tests/stress.c @@ -1,4 +1,3 @@ -#define TEST_MACROS #include "tests.h" #include <camellia/flags.h> #include <camellia/syscalls.h> diff --git a/src/user/app/tests/tests.c b/src/user/app/tests/tests.c index 5c40bcd..a6e7d52 100644 --- a/src/user/app/tests/tests.c +++ b/src/user/app/tests/tests.c @@ -1,312 +1,23 @@ -#define TEST_MACROS #include "tests.h" -#include <camellia/errno.h> -#include <camellia/execbuf.h> -#include <camellia/flags.h> #include <camellia/syscalls.h> -#include <stdlib.h> -#include <string.h> #include <unistd.h> -static void run_forked(void (*fn)()) { +void run_test(void (*fn)()) { if (!fork()) { fn(); exit(0); } else { - /* successful tests must return 0 - * TODO add a better fail msg */ + /* successful tests must return 0 */ if (_syscall_await() != 0) test_fail(); } } - -const char *tmpfilepath = "/tmp/.test_internal"; - -static void test_await(void) { - /* creates 16 child processes, each returning a different value. then checks - * if await() returns every value exactly once */ - int ret; - int counts[16] = {0}; - - for (int i = 0; i < 16; i++) - if (!fork()) - exit(i); - - while ((ret = _syscall_await()) != ~0) { - assert(0 <= ret && ret < 16); - counts[ret]++; - } - - for (int i = 0; i < 16; i++) - assert(counts[i] == 1); -} - -static void test_faults(void) { - /* tests what happens when child processes fault. - * expected behavior: parent processes still manages to finish, and it can - * reap all its children */ - int await_cnt = 0; - - if (!fork()) { // invalid memory access - asm volatile("movb $69, 0" ::: "memory"); - printf("this shouldn't happen"); - exit(-1); - } - if (!fork()) { // #GP - asm volatile("hlt" ::: "memory"); - printf("this shouldn't happen"); - exit(-1); - } - - while (_syscall_await() != ~0) await_cnt++; - assert(await_cnt == 2); -} - -static void test_interrupted_fs(void) { - handle_t h; - if (_syscall_fork(FORK_NEWFS, &h)) { /* child */ - // TODO make a similar test with all 0s passed to fs_wait - struct fs_wait_response res; - _syscall_fs_wait(NULL, 0, &res); - exit(0); - } else { /* parent */ - _syscall_mount(h, "/", 1); - int ret = _syscall_open("/", 1, 0); - // the handler quits while handling that call - but this syscall should return anyways - exit(ret < 0 ? 0 : -1); - } -} - -static void test_orphaned_fs(void) { - handle_t h; - if (_syscall_fork(FORK_NEWFS, &h)) { /* child */ - exit(0); - } else { /* parent */ - _syscall_mount(h, "/", 1); - int ret = _syscall_open("/", 1, 0); - // no handler will ever be available to handle this call - the syscall should instantly return - exit(ret < 0 ? 0 : -1); - } -} - -static void test_memflag(void) { - void *page = (void*)0x77777000; - _syscall_memflag(page, 4096, MEMFLAG_PRESENT); // allocate page - memset(page, 77, 4096); // write to it - _syscall_memflag(page, 4096, 0); // free it - - if (!fork()) { - memset(page, 11, 4096); // should segfault - exit(0); - } else { - assert(_syscall_await() != 0); // test if the process crashed - } - - char *pages[4]; - for (size_t i = 0; i < 4; i++) { - pages[i] = _syscall_memflag(NULL, 4096, MEMFLAG_FINDFREE); - printf("[test_memflag] findfree: 0x%x\n", pages[i]); - - assert(pages[i] == _syscall_memflag(NULL, 4096, MEMFLAG_FINDFREE | MEMFLAG_PRESENT)); - if (i > 0) assert(pages[i] != pages[i-1]); - *pages[i] = 0x77; - } - - for (size_t i = 0; i < 4; i++) - _syscall_memflag(pages, 4096, MEMFLAG_PRESENT); - - // TODO check if reclaims -} - -static void test_dup(void) { - handle_t pipe[2]; - handle_t h1, h2; - assert(_syscall_pipe(pipe, 0) >= 0); - - if (!fork()) { - close(pipe[0]); - - h1 = _syscall_dup(pipe[1], -1, 0); - assert(h1 >= 0); - assert(h1 != pipe[1]); - h2 = _syscall_dup(h1, -1, 0); - assert(h2 >= 0); - assert(h2 != pipe[1] && h2 != h1); - - _syscall_write(pipe[1], "og", 2, 0, 0); - _syscall_write(h1, "h1", 2, 0, 0); - _syscall_write(h2, "h2", 2, 0, 0); - - close(pipe[1]); - _syscall_write(h1, "h1", 2, 0, 0); - _syscall_write(h2, "h2", 2, 0, 0); - - assert(_syscall_dup(h1, pipe[1], 0) == pipe[1]); - assert(_syscall_dup(h2, pipe[1], 0) == pipe[1]); - assert(_syscall_dup(h1, pipe[1], 0) == pipe[1]); - assert(_syscall_dup(h2, pipe[1], 0) == pipe[1]); - close(h1); - close(h2); - - assert(_syscall_dup(pipe[1], h2, 0) == h2); - _syscall_write(h2, "h2", 2, 0, 0); - close(h2); - - assert(_syscall_dup(pipe[1], h1, 0) == h1); - _syscall_write(h1, "h1", 2, 0, 0); - close(h1); - - exit(0); - } else { - char buf[16]; - size_t count = 0; - close(pipe[1]); - while (_syscall_read(pipe[0], buf, sizeof buf, 0) >= 0) - count++; - assert(count == 7); - _syscall_await(); - } - - - close(pipe[0]); -} - -static void test_malloc(void) { - // not really a test - void *p1, *p2; - - p1 = malloc(420); - printf("p1 = 0x%x\n", p1); - - p2 = malloc(1024); - printf("p2 = 0x%x\n", p2); - free(p2); - p2 = malloc(256); - printf("p2 = 0x%x\n", p2); - free(p2); - p2 = malloc(4096); - printf("p2 = 0x%x\n", p2); - free(p2); - - free(p1); -} - -static void test_efault(void) { - const char *str = "o, 16 characters"; - char str2[16]; - char *invalid = (void*)0x1000; - handle_t h; - - memcpy(str2, str, 16); - - assert((h = _syscall_open(tmpfilepath, strlen(tmpfilepath), OPEN_CREATE))); - assert(_syscall_write(h, str, 16, 0, 0) == 16); - assert(_syscall_write(h, str2, 16, 0, 0) == 16); - - assert(_syscall_write(h, invalid, 16, 0, 0) == -EFAULT); - - /* x64 canonical pointers */ - assert(_syscall_write(h, (void*)((uintptr_t)str ^ 0x8000000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str ^ 0x1000000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str ^ 0x0100000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str ^ 0x0010000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str ^ 0x0001000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str ^ 0x0000800000000000), 16, 0, 0) == -EFAULT); - - assert(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x8000000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x1000000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x0100000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x0010000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x0001000000000000), 16, 0, 0) == -EFAULT); - assert(_syscall_write(h, (void*)((uintptr_t)str2 ^ 0x0000800000000000), 16, 0, 0) == -EFAULT); - - assert(_syscall_write(h, str, 16, 0, 0) == 16); - close(h); -} - -static void test_execbuf(void) { - // not really a test, TODO - const char str1[] = "test_execbuf: string 1\n"; - const char str2[] = "test_execbuf: and 2\n"; - uint64_t buf[] = { - EXECBUF_SYSCALL, _SYSCALL_WRITE, 1, (uintptr_t)str1, sizeof(str1) - 1, -1, 0, - EXECBUF_SYSCALL, _SYSCALL_WRITE, 1, (uintptr_t)str2, sizeof(str2) - 1, -1, 0, - EXECBUF_SYSCALL, _SYSCALL_EXIT, 0, 0, 0, 0, 0, - }; - _syscall_execbuf(buf, sizeof buf); - test_fail(); -} - -static void test_strtol(void) { - char *end; - assert(1234 == strtol("1234", NULL, 10)); - assert(1234 == strtol("+1234", NULL, 10)); - assert(-1234 == strtol("-1234", NULL, 10)); - - assert(1234 == strtol("1234", &end, 10)); - assert(!strcmp("", end)); - assert(1234 == strtol(" 1234hello", &end, 10)); - assert(!strcmp("hello", end)); - - assert(1234 == strtol(" 1234hello", &end, 0)); - assert(!strcmp("hello", end)); - assert(0xCAF3 == strtol(" 0xCaF3hello", &end, 0)); - assert(!strcmp("hello", end)); - assert(01234 == strtol(" 01234hello", &end, 0)); - assert(!strcmp("hello", end)); -} - -static void test_sleep(void) { - // TODO yet another of those fake tests that you have to verify by hand - if (!fork()) { - if (!fork()) { - _syscall_sleep(100); - printf("1\n"); - _syscall_sleep(200); - printf("3\n"); - _syscall_sleep(200); - printf("5\n"); - _syscall_exit(0); - } - if (!fork()) { - printf("0\n"); - _syscall_sleep(200); - printf("2\n"); - _syscall_sleep(200); - printf("4\n"); - /* get killed while asleep - * a peaceful death, i suppose. */ - for (;;) _syscall_sleep(1000000000); - } - _syscall_await(); - _syscall_exit(0); - } - - /* this part checks if, after killing an asleep process, other processes can still wake up */ - _syscall_sleep(600); - printf("6\n"); -} - -static void test_misc(void) { - assert(_syscall(~0, 0, 0, 0, 0, 0) < 0); /* try making an invalid syscall */ -} - - int main(void) { - run_forked(test_await); - run_forked(test_faults); - run_forked(test_interrupted_fs); - run_forked(test_orphaned_fs); - run_forked(test_memflag); - run_forked(test_dup); - run_forked(test_malloc); - run_forked(test_pipe); - run_forked(test_semaphore); - run_forked(test_efault); - run_forked(test_execbuf); - run_forked(test_printf); - run_forked(test_strtol); - run_forked(test_sleep); - run_forked(test_misc); - return 1; + r_k_fs(); + r_k_misc(); + r_k_miscsyscall(); + r_libc_esemaphore(); + r_libc_string(); + r_printf(); + return 0; } diff --git a/src/user/app/tests/tests.h b/src/user/app/tests/tests.h index 5f36fe0..974014a 100644 --- a/src/user/app/tests/tests.h +++ b/src/user/app/tests/tests.h @@ -3,20 +3,20 @@ #include <stdio.h> #include <unistd.h> -void stress_all(void); -void test_all(void); +#define TMPFILEPATH "/tmp/.test_internal" -void test_pipe(void); -void test_printf(void); -void test_semaphore(void); +void run_test(void (*fn)()); -#ifdef TEST_MACROS +void r_k_fs(void); +void r_k_misc(void); +void r_k_miscsyscall(void); +void r_libc_esemaphore(void); +void r_libc_string(void); +void r_printf(void); #define argify(str) str, sizeof(str) - 1 #define test_fail() do { \ printf("\033[31m" "TEST FAILED: %s():%u\n" "\033[0m", __func__, __LINE__); \ exit(0); \ } while (0) -#define assert(cond) if (!(cond)) test_fail(); - -#endif +#define test(cond) if (!(cond)) test_fail(); |