From 56583b1402a7f8fad0f8c3c296e26f12b1114c95 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Thu, 3 Oct 2019 15:02:19 -0400 Subject: updated alarmtest --- user/alarmtest.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'user') diff --git a/user/alarmtest.c b/user/alarmtest.c index ca3db23..d3746c4 100644 --- a/user/alarmtest.c +++ b/user/alarmtest.c @@ -21,7 +21,7 @@ main(int argc, char *argv[]) { test0(); test1(); - exit(); + exit(0); } volatile static int count; @@ -44,7 +44,7 @@ test0() count = 0; sigalarm(2, periodic); for(i = 0; i < 1000*500000; i++){ - if((i % 250000) == 0) + if((i % 1000000) == 0) write(2, ".", 1); if(count > 0) break; @@ -53,7 +53,7 @@ test0() if(count > 0){ printf("test0 passed\n"); } else { - printf("test0 failed\n"); + printf("\ntest0 failed: the kernel never called the alarm handler\n"); } } @@ -64,6 +64,14 @@ void __attribute__ ((noinline)) foo(int i, int *j) { *j += 1; } +// +// tests that the kernel calls the handler multiple times. +// +// tests that, when the handler returns, it returns to +// the point in the program where the timer interrupt +// occurred, with all registers holding the same values they +// held when the interrupt occurred. +// void test1() { @@ -79,9 +87,19 @@ test1() break; foo(i, &j); } - if(i != j || count < 10){ - // i should equal j - printf("test1 failed\n"); + if(count < 10){ + printf("\ntest1 failed: too few calls to the handler\n"); + exit(1); + } else if(i != j){ + // the loop should have called foo() i times, and foo() should + // have incremented j once per call, so j should equal i. + // once possible source of errors is that the handler may + // return somewhere other than where the timer interrupt + // occurred; another is that that registers may not be + // restored correctly, causing i or j or the address ofj + // to get an incorrect value. + printf("\ntest1 failed: foo() executed fewer times than it was called\n"); + exit(1); } else { printf("test1 passed\n"); } -- cgit v1.2.3 From a52d296814d869f16ced4fb68246223b4a64fa38 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Thu, 3 Oct 2019 15:09:31 -0400 Subject: delete alarmtest from riscv --- user/alarmtest.c | 106 ------------------------------------------------------- 1 file changed, 106 deletions(-) delete mode 100644 user/alarmtest.c (limited to 'user') diff --git a/user/alarmtest.c b/user/alarmtest.c deleted file mode 100644 index d3746c4..0000000 --- a/user/alarmtest.c +++ /dev/null @@ -1,106 +0,0 @@ -// -// test program for the alarm lab. -// you can modify this file for testing, -// but please make sure your kernel -// modifications pass the original -// versions of these tests. -// - -#include "kernel/param.h" -#include "kernel/types.h" -#include "kernel/stat.h" -#include "kernel/riscv.h" -#include "user/user.h" - -void test0(); -void test1(); -void periodic(); - -int -main(int argc, char *argv[]) -{ - test0(); - test1(); - exit(0); -} - -volatile static int count; - -void -periodic() -{ - count = count + 1; - printf("alarm!\n"); - sigreturn(); -} - -// tests whether the kernel calls -// the alarm handler even a single time. -void -test0() -{ - int i; - printf("test0 start\n"); - count = 0; - sigalarm(2, periodic); - for(i = 0; i < 1000*500000; i++){ - if((i % 1000000) == 0) - write(2, ".", 1); - if(count > 0) - break; - } - sigalarm(0, 0); - if(count > 0){ - printf("test0 passed\n"); - } else { - printf("\ntest0 failed: the kernel never called the alarm handler\n"); - } -} - -void __attribute__ ((noinline)) foo(int i, int *j) { - if((i % 2500000) == 0) { - write(2, ".", 1); - } - *j += 1; -} - -// -// tests that the kernel calls the handler multiple times. -// -// tests that, when the handler returns, it returns to -// the point in the program where the timer interrupt -// occurred, with all registers holding the same values they -// held when the interrupt occurred. -// -void -test1() -{ - int i; - int j; - - printf("test1 start\n"); - count = 0; - j = 0; - sigalarm(2, periodic); - for(i = 0; i < 500000000; i++){ - if(count >= 10) - break; - foo(i, &j); - } - if(count < 10){ - printf("\ntest1 failed: too few calls to the handler\n"); - exit(1); - } else if(i != j){ - // the loop should have called foo() i times, and foo() should - // have incremented j once per call, so j should equal i. - // once possible source of errors is that the handler may - // return somewhere other than where the timer interrupt - // occurred; another is that that registers may not be - // restored correctly, causing i or j or the address ofj - // to get an incorrect value. - printf("\ntest1 failed: foo() executed fewer times than it was called\n"); - exit(1); - } else { - printf("test1 passed\n"); - } -} -- cgit v1.2.3 From 8509784d8000d6791a205626e81b03b3f9bf856b Mon Sep 17 00:00:00 2001 From: Anish Athalye Date: Tue, 8 Oct 2019 21:18:54 -0400 Subject: Add implementations of memcmp and memcpy to ulib This is necessary because gcc may generate calls to memcmp, memset, memcpy, and memmove when compiling with -nostdlib. --- user/ulib.c | 20 ++++++++++++++++++++ user/user.h | 2 ++ 2 files changed, 22 insertions(+) (limited to 'user') diff --git a/user/ulib.c b/user/ulib.c index ddda0f5..8bfba5d 100644 --- a/user/ulib.c +++ b/user/ulib.c @@ -107,3 +107,23 @@ memmove(void *vdst, const void *vsrc, int n) *dst++ = *src++; return vdst; } + +int +memcmp(const void *s1, const void *s2, uint n) +{ + const char *p1 = s1, *p2 = s2; + while (n-- > 0) { + if (*p1 != *p2) { + return *p1 - *p2; + } + p1++; + p2++; + } + return 0; +} + +void * +memcpy(void *dst, const void *src, uint n) +{ + return memmove(dst, src, n); +} diff --git a/user/user.h b/user/user.h index 03af731..b71ecda 100644 --- a/user/user.h +++ b/user/user.h @@ -38,3 +38,5 @@ void* memset(void*, int, uint); void* malloc(uint); void free(void*); int atoi(const char*); +int memcmp(const void *, const void *, uint); +void *memcpy(void *, const void *, uint); -- cgit v1.2.3 From f2df0fa5471c9951ff9a12bea51efbe22afb196e Mon Sep 17 00:00:00 2001 From: Anish Athalye Date: Tue, 8 Oct 2019 21:24:03 -0400 Subject: Fix ulib's memmove to handle overlap when src 0) - *dst++ = *src++; + if (src > dst) { + while(n-- > 0) + *dst++ = *src++; + } else { + dst += n; + src += n; + while(n-- > 0) + *--dst = *--src; + } return vdst; } -- cgit v1.2.3 From d9160fb4b98e3ce04d3928c1fbd2ec26b3cc746a Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Sun, 27 Oct 2019 08:03:19 -0400 Subject: nits --- user/usertests.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'user') diff --git a/user/usertests.c b/user/usertests.c index db9f680..eb10ee2 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -2105,9 +2105,9 @@ run(void f(char *), char *s) { } else { wait(&xstatus); if(xstatus != 0) - printf("FAILED\n", s); + printf("FAILED\n"); else - printf("OK\n", s); + printf("OK\n"); return xstatus == 0; } } -- cgit v1.2.3 From 9de9211b1158bfbe169c5099dae11432d5950105 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Mon, 28 Oct 2019 05:58:28 -0400 Subject: usertests -c to repeat tests forever detect memory leaks no more "already ran user tests" --- user/usertests.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 16 deletions(-) (limited to 'user') diff --git a/user/usertests.c b/user/usertests.c index eb10ee2..8d1d06a 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -1418,6 +1418,14 @@ fourteen(char *s) printf("%s: mkdir 12345678901234/123456789012345 succeeded!\n", s); exit(1); } + + // clean up + unlink("123456789012345/12345678901234"); + unlink("12345678901234/12345678901234"); + unlink("12345678901234/12345678901234/12345678901234"); + unlink("123456789012345/123456789012345/123456789012345"); + unlink("12345678901234/123456789012345"); + unlink("12345678901234"); } void @@ -1512,7 +1520,8 @@ dirfile(char *s) close(fd); } -// test that iput() is called at the end of _namei() +// test that iput() is called at the end of _namei(). +// also tests empty file names. void iref(char *s) { @@ -1539,6 +1548,12 @@ iref(char *s) unlink("xx"); } + // clean up + for(i = 0; i < NINODE + 1; i++){ + chdir(".."); + unlink("irefd"); + } + chdir("/"); } @@ -2087,13 +2102,32 @@ badarg(char *s) exit(0); } +// +// use sbrk() to count how many free physical memory pages there are. +// +int +countfree() +{ + uint64 sz0 = (uint64)sbrk(0); + int n = 0; + + while(1){ + if((uint64)sbrk(4096) == 0xffffffffffffffff){ + break; + } + n += 1; + } + sbrk(-((uint64)sbrk(0) - sz0)); + return n; +} + // run each test in its own process. run returns 1 if child's exit() // indicates success. int run(void f(char *), char *s) { int pid; int xstatus; - + printf("test %s: ", s); if((pid = fork()) < 0) { printf("runtest: fork error\n"); @@ -2115,9 +2149,16 @@ run(void f(char *), char *s) { int main(int argc, char *argv[]) { - char *n = 0; - if(argc > 1) { - n = argv[1]; + int continuous = 0; + char *justone = 0; + + if(argc == 2 && strcmp(argv[1], "-c") == 0){ + continuous = 1; + } else if(argc == 2 && argv[1][0] != '-'){ + justone = argv[1]; + } else if(argc > 1){ + printf("Usage: usertests [-c] [testname]\n"); + exit(1); } struct test { @@ -2173,25 +2214,48 @@ main(int argc, char *argv[]) {bigdir, "bigdir"}, // slow { 0, 0}, }; - - printf("usertests starting\n"); - if(open("usertests.ran", 0) >= 0){ - printf("already ran user tests -- rebuild fs.img (rm fs.img; make fs.img)\n"); - exit(1); + if(continuous){ + printf("continuous usertests starting\n"); + while(1){ + int fail = 0; + int free0 = countfree(); + for (struct test *t = tests; t->s != 0; t++) { + if(!run(t->f, t->s)){ + fail = 1; + break; + } + } + if(fail){ + printf("SOME TESTS FAILED\n"); + exit(1); + } + int free1 = countfree(); + if(free1 < free0){ + printf("FAILED -- lost some free pages\n"); + exit(1); + } + } } - close(open("usertests.ran", O_CREATE)); + printf("usertests starting\n"); + int free0 = countfree(); int fail = 0; for (struct test *t = tests; t->s != 0; t++) { - if((n == 0) || strcmp(t->s, n) == 0) { + if((justone == 0) || strcmp(t->s, justone) == 0) { if(!run(t->f, t->s)) fail = 1; } } - if(!fail) - printf("ALL TESTS PASSED\n"); - else + + if(fail){ printf("SOME TESTS FAILED\n"); - exit(1); // not reached. + exit(1); + } else if(countfree() < free0){ + printf("FAILED -- lost some free pages\n"); + exit(1); + } else { + printf("ALL TESTS PASSED\n"); + exit(0); + } } -- cgit v1.2.3 From 16b3b63f06c1ea17da484aeebea4a57fb2a6e44a Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Wed, 6 Nov 2019 11:18:43 -0500 Subject: grind: run parallel system calls forever --- user/grind.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ user/usertests.c | 14 +++-- 2 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 user/grind.c (limited to 'user') diff --git a/user/grind.c b/user/grind.c new file mode 100644 index 0000000..97a8a93 --- /dev/null +++ b/user/grind.c @@ -0,0 +1,160 @@ +// +// run random system calls in parallel forever. +// + +#include "kernel/param.h" +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" +#include "kernel/fs.h" +#include "kernel/fcntl.h" +#include "kernel/syscall.h" +#include "kernel/memlayout.h" +#include "kernel/riscv.h" + +// from FreeBSD. +int +do_rand(unsigned long *ctx) +{ +/* + * Compute x = (7^5 * x) mod (2^31 - 1) + * without overflowing 31 bits: + * (2^31 - 1) = 127773 * (7^5) + 2836 + * From "Random number generators: good ones are hard to find", + * Park and Miller, Communications of the ACM, vol. 31, no. 10, + * October 1988, p. 1195. + */ + long hi, lo, x; + + /* Transform to [1, 0x7ffffffe] range. */ + x = (*ctx % 0x7ffffffe) + 1; + hi = x / 127773; + lo = x % 127773; + x = 16807 * lo - 2836 * hi; + if (x < 0) + x += 0x7fffffff; + /* Transform to [0, 0x7ffffffd] range. */ + x--; + *ctx = x; + return (x); +} + +unsigned long rand_next = 1; + +int +rand(void) +{ + return (do_rand(&rand_next)); +} + +void +go() +{ + int fd = -1; + static char buf[999]; + char *break0 = sbrk(0); + + while(1){ + int what = rand() % 20; + if(what == 1){ + close(open("a", O_CREATE|O_RDWR)); + } else if(what == 2){ + close(open("b", O_CREATE|O_RDWR)); + } else if(what == 3){ + unlink("a"); + } else if(what == 4){ + unlink("b"); + } else if(what == 5){ + close(fd); + fd = open("a", O_CREATE|O_RDWR); + } else if(what == 6){ + close(fd); + fd = open("b", O_CREATE|O_RDWR); + } else if(what == 7){ + write(fd, buf, sizeof(buf)); + } else if(what == 8){ + read(fd, buf, sizeof(buf)); + } else if(what == 9){ + mkdir("a"); + } else if(what == 10){ + mkdir("b"); + } else if(what == 11){ + unlink("b"); + link("a", "b"); + } else if(what == 12){ + unlink("a"); + link("b", "a"); + } else if(what == 13){ + int pid = fork(); + if(pid == 0){ + exit(0); + } + wait(0); + } else if(what == 14){ + int pid = fork(); + if(pid == 0){ + fork(); + fork(); + exit(0); + } + wait(0); + } else if(what == 15){ + sbrk(6011); + } else if(what == 16){ + if(sbrk(0) > break0) + sbrk(-(sbrk(0) - break0)); + } else if(what == 17){ + int pid = fork(); + if(pid == 0){ + close(open("a", O_CREATE|O_RDWR)); + exit(0); + } + kill(pid); + wait(0); + } else if(what == 18){ + int pid = fork(); + if(pid == 0){ + kill(getpid()); + exit(0); + } + wait(0); + } + } +} + +int +main() +{ + int pid1 = fork(); + if(pid1 < 0){ + printf("grind: fork failed\n"); + exit(1); + } + if(pid1 == 0){ + rand_next = 31; + go(); + exit(0); + } + + int pid2 = fork(); + if(pid2 < 0){ + printf("grind: fork failed\n"); + exit(1); + } + if(pid2 == 0){ + rand_next = 7177; + go(); + exit(0); + } + + int st1 = -1; + wait(&st1); + if(st1 != 0){ + kill(pid1); + kill(pid2); + } + int st2 = -1; + wait(&st2); + + exit(0); +} diff --git a/user/usertests.c b/user/usertests.c index 8d1d06a..9aa0ed4 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -1038,11 +1038,15 @@ concreate(char *s) close(open(file, 0)); close(open(file, 0)); close(open(file, 0)); + close(open(file, 0)); + close(open(file, 0)); } else { unlink(file); unlink(file); unlink(file); unlink(file); + unlink(file); + unlink(file); } if(pid == 0) exit(0); @@ -1106,7 +1110,7 @@ bigdir(char *s) name[2] = '0' + (i % 64); name[3] = '\0'; if(link("bd", name) != 0){ - printf("%s: bigdir link failed\n", s); + printf("%s: bigdir link(bd, %s) failed\n", s, name); exit(1); } } @@ -1335,8 +1339,8 @@ bigfile(char *s) enum { N = 20, SZ=600 }; int fd, i, total, cc; - unlink("bigfile"); - fd = open("bigfile", O_CREATE | O_RDWR); + unlink("bigfile.dat"); + fd = open("bigfile.dat", O_CREATE | O_RDWR); if(fd < 0){ printf("%s: cannot create bigfile", s); exit(1); @@ -1350,7 +1354,7 @@ bigfile(char *s) } close(fd); - fd = open("bigfile", 0); + fd = open("bigfile.dat", 0); if(fd < 0){ printf("%s: cannot open bigfile\n", s); exit(1); @@ -1379,7 +1383,7 @@ bigfile(char *s) printf("%s: read bigfile wrong total\n", s); exit(1); } - unlink("bigfile"); + unlink("bigfile.dat"); } void -- cgit v1.2.3 From 20f1dd940964d7e01cf8c8d9b1a5b751840b7f3b Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Thu, 7 Nov 2019 06:44:23 -0500 Subject: more grind --- user/grind.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) (limited to 'user') diff --git a/user/grind.c b/user/grind.c index 97a8a93..a01271e 100644 --- a/user/grind.c +++ b/user/grind.c @@ -48,13 +48,17 @@ rand(void) } void -go() +go(int which_child) { int fd = -1; static char buf[999]; char *break0 = sbrk(0); + uint64 iters = 0; while(1){ + iters++; + if((iters % 500) == 0) + write(1, which_child?"B":"A", 1); int what = rand() % 20; if(what == 1){ close(open("a", O_CREATE|O_RDWR)); @@ -76,8 +80,12 @@ go() read(fd, buf, sizeof(buf)); } else if(what == 9){ mkdir("a"); + close(open("a/a", O_CREATE|O_RDWR)); + unlink("a/a"); } else if(what == 10){ mkdir("b"); + close(open("b/b", O_CREATE|O_RDWR)); + unlink("b/b"); } else if(what == 11){ unlink("b"); link("a", "b"); @@ -88,6 +96,9 @@ go() int pid = fork(); if(pid == 0){ exit(0); + } else if(pid < 0){ + printf("grind: fork failed\n"); + exit(1); } wait(0); } else if(what == 14){ @@ -96,6 +107,9 @@ go() fork(); fork(); exit(0); + } else if(pid < 0){ + printf("grind: fork failed\n"); + exit(1); } wait(0); } else if(what == 15){ @@ -108,6 +122,9 @@ go() if(pid == 0){ close(open("a", O_CREATE|O_RDWR)); exit(0); + } else if(pid < 0){ + printf("grind: fork failed\n"); + exit(1); } kill(pid); wait(0); @@ -116,8 +133,34 @@ go() if(pid == 0){ kill(getpid()); exit(0); + } else if(pid < 0){ + printf("grind: fork failed\n"); + exit(1); } wait(0); + } else if(what == 19){ + int fds[2]; + if(pipe(fds) < 0){ + printf("grind: pipe failed\n"); + exit(1); + } + int pid = fork(); + if(pid == 0){ + fork(); + fork(); + if(write(fds[1], "x", 1) != 1) + printf("grind: pipe write failed\n"); + char c; + if(read(fds[0], &c, 1) != 1) + printf("grind: pipe read failed\n"); + exit(0); + } else if(pid < 0){ + printf("grind: fork failed\n"); + exit(1); + } + close(fds[0]); + close(fds[1]); + wait(0); } } } @@ -125,6 +168,9 @@ go() int main() { + unlink("a"); + unlink("b"); + int pid1 = fork(); if(pid1 < 0){ printf("grind: fork failed\n"); @@ -132,7 +178,7 @@ main() } if(pid1 == 0){ rand_next = 31; - go(); + go(0); exit(0); } @@ -143,7 +189,7 @@ main() } if(pid2 == 0){ rand_next = 7177; - go(); + go(1); exit(0); } -- cgit v1.2.3 From b62d4d412bf36eb445dd05cf80762ba8837de6ce Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Thu, 7 Nov 2019 09:46:20 -0500 Subject: more grind --- user/cat.c | 8 +-- user/grind.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 145 insertions(+), 18 deletions(-) (limited to 'user') diff --git a/user/cat.c b/user/cat.c index 36939d8..598f005 100644 --- a/user/cat.c +++ b/user/cat.c @@ -11,12 +11,12 @@ cat(int fd) while((n = read(fd, buf, sizeof(buf))) > 0) { if (write(1, buf, n) != n) { - printf("cat: write error\n"); + fprintf(2, "cat: write error\n"); exit(1); } } if(n < 0){ - printf("cat: read error\n"); + fprintf(2, "cat: read error\n"); exit(1); } } @@ -28,12 +28,12 @@ main(int argc, char *argv[]) if(argc <= 1){ cat(0); - exit(1); + exit(0); } for(i = 1; i < argc; i++){ if((fd = open(argv[i], 0)) < 0){ - printf("cat: cannot open %s\n", argv[i]); + fprintf(2, "cat: cannot open %s\n", argv[i]); exit(1); } cat(fd); diff --git a/user/grind.c b/user/grind.c index a01271e..6203e57 100644 --- a/user/grind.c +++ b/user/grind.c @@ -54,44 +54,56 @@ go(int which_child) static char buf[999]; char *break0 = sbrk(0); uint64 iters = 0; + + mkdir("grindir"); + if(chdir("grindir") != 0){ + printf("chdir grindir failed\n"); + exit(1); + } + chdir("/"); while(1){ iters++; if((iters % 500) == 0) write(1, which_child?"B":"A", 1); - int what = rand() % 20; + int what = rand() % 23; if(what == 1){ - close(open("a", O_CREATE|O_RDWR)); + close(open("grindir/../a", O_CREATE|O_RDWR)); } else if(what == 2){ - close(open("b", O_CREATE|O_RDWR)); + close(open("grindir/../grindir/../b", O_CREATE|O_RDWR)); } else if(what == 3){ - unlink("a"); + unlink("grindir/../a"); } else if(what == 4){ - unlink("b"); + if(chdir("grindir") != 0){ + printf("chdir grindir failed\n"); + exit(1); + } + unlink("../b"); + chdir("/"); } else if(what == 5){ close(fd); - fd = open("a", O_CREATE|O_RDWR); + fd = open("/grindir/../a", O_CREATE|O_RDWR); } else if(what == 6){ close(fd); - fd = open("b", O_CREATE|O_RDWR); + fd = open("/./grindir/./../b", O_CREATE|O_RDWR); } else if(what == 7){ write(fd, buf, sizeof(buf)); } else if(what == 8){ read(fd, buf, sizeof(buf)); } else if(what == 9){ - mkdir("a"); - close(open("a/a", O_CREATE|O_RDWR)); + mkdir("grindir/../a"); + close(open("a/../a/./a", O_CREATE|O_RDWR)); unlink("a/a"); } else if(what == 10){ - mkdir("b"); - close(open("b/b", O_CREATE|O_RDWR)); + mkdir("/../b"); + close(open("grindir/../b/b", O_CREATE|O_RDWR)); unlink("b/b"); } else if(what == 11){ unlink("b"); - link("a", "b"); + link("../grindir/./../a", "../b"); } else if(what == 12){ - unlink("a"); - link("b", "a"); + unlink("../grindir/../a"); + link(".././b", "/grindir/../a"); } else if(what == 13){ int pid = fork(); if(pid == 0){ @@ -126,6 +138,10 @@ go(int which_child) printf("grind: fork failed\n"); exit(1); } + if(chdir("../grindir/..") != 0){ + printf("chdir failed\n"); + exit(1); + } kill(pid); wait(0); } else if(what == 18){ @@ -161,6 +177,117 @@ go(int which_child) close(fds[0]); close(fds[1]); wait(0); + } else if(what == 20){ + int pid = fork(); + if(pid == 0){ + unlink("a"); + mkdir("a"); + chdir("a"); + unlink("../a"); + fd = open("x", O_CREATE|O_RDWR); + unlink("x"); + exit(0); + } else if(pid < 0){ + printf("fork failed\n"); + exit(1); + } + wait(0); + } else if(what == 21){ + unlink("c"); + // should always succeed. check that there are free i-nodes, + // file descriptors, blocks. + int fd1 = open("c", O_CREATE|O_RDWR); + if(fd1 < 0){ + printf("create c failed\n"); + exit(1); + } + if(write(fd1, "x", 1) != 1){ + printf("write c failed\n"); + exit(1); + } + struct stat st; + if(fstat(fd1, &st) != 0){ + printf("fstat failed\n"); + exit(1); + } + if(st.size != 1){ + printf("fstat reports wrong size %d\n", (int)st.size); + exit(1); + } + if(st.ino > 50){ + printf("fstat reports crazy i-number %d\n", st.ino); + exit(1); + } + close(fd1); + unlink("c"); + } else if(what == 22){ + // echo hi | cat + int aa[2], bb[2]; + if(pipe(aa) < 0){ + fprintf(2, "pipe failed\n"); + exit(1); + } + if(pipe(bb) < 0){ + fprintf(2, "pipe failed\n"); + exit(1); + } + int pid1 = fork(); + if(pid1 == 0){ + close(bb[0]); + close(bb[1]); + close(aa[0]); + close(1); + if(dup(aa[1]) != 1){ + fprintf(2, "dup failed\n"); + exit(1); + } + close(aa[1]); + char *args[3] = { "echo", "hi", 0 }; + exec("grindir/../echo", args); + fprintf(2, "echo: not found\n"); + exit(2); + } else if(pid1 < 0){ + fprintf(2, "fork failed\n"); + exit(3); + } + int pid2 = fork(); + if(pid2 == 0){ + close(aa[1]); + close(bb[0]); + close(0); + if(dup(aa[0]) != 0){ + fprintf(2, "dup failed\n"); + exit(4); + } + close(aa[0]); + close(1); + if(dup(bb[1]) != 1){ + fprintf(2, "dup failed\n"); + exit(5); + } + close(bb[1]); + char *args[2] = { "cat", 0 }; + exec("/cat", args); + fprintf(2, "cat: not found\n"); + exit(6); + } else if(pid2 < 0){ + fprintf(2, "fork failed\n"); + exit(7); + } + close(aa[0]); + close(aa[1]); + close(bb[1]); + char buf[3] = { 0, 0, 0 }; + read(bb[0], buf+0, 1); + read(bb[0], buf+1, 1); + close(bb[0]); + int st1, st2; + wait(&st1); + wait(&st2); + if(st1 != 0 || st2 != 0 || strcmp(buf, "hi") != 0){ + printf("exec pipeline failed %d %d \"%s\"\n", st1, st2, buf); + exit(1); + } } } } -- cgit v1.2.3 From 672217ae2a3d68b73b2229ab368979ef7790e28a Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Fri, 8 Nov 2019 13:21:06 -0500 Subject: allow more files --- user/grind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'user') diff --git a/user/grind.c b/user/grind.c index 6203e57..14e2aae 100644 --- a/user/grind.c +++ b/user/grind.c @@ -214,7 +214,7 @@ go(int which_child) printf("fstat reports wrong size %d\n", (int)st.size); exit(1); } - if(st.ino > 50){ + if(st.ino > 200){ printf("fstat reports crazy i-number %d\n", st.ino); exit(1); } -- cgit v1.2.3 From af9eb9114c2f8700d4315eaa1e2d637c2aaaf210 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Thu, 16 Jul 2020 11:38:08 -0400 Subject: make "echo hello > x" truncate file x. --- user/sh.c | 2 +- user/usertests.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 1 deletion(-) (limited to 'user') diff --git a/user/sh.c b/user/sh.c index a593bc0..83dd513 100644 --- a/user/sh.c +++ b/user/sh.c @@ -386,7 +386,7 @@ parseredirs(struct cmd *cmd, char **ps, char *es) cmd = redircmd(cmd, q, eq, O_RDONLY, 0); break; case '>': - cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); + cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1); break; case '+': // >> cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); diff --git a/user/usertests.c b/user/usertests.c index 9aa0ed4..f83a060 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -22,6 +22,141 @@ char buf[BUFSZ]; char name[3]; +// test O_TRUNC. +void +truncate1(char *s) +{ + char buf[32]; + + unlink("truncfile"); + int fd1 = open("truncfile", O_CREATE|O_WRONLY|O_TRUNC); + write(fd1, "abcd", 4); + close(fd1); + + int fd2 = open("truncfile", O_RDONLY); + int n = read(fd2, buf, sizeof(buf)); + if(n != 4){ + printf("%s: read %d bytes, wanted 4\n", s, n); + exit(1); + } + + fd1 = open("truncfile", O_WRONLY|O_TRUNC); + + int fd3 = open("truncfile", O_RDONLY); + n = read(fd3, buf, sizeof(buf)); + if(n != 0){ + printf("aaa fd3=%d\n", fd3); + printf("%s: read %d bytes, wanted 0\n", s, n); + exit(1); + } + + n = read(fd2, buf, sizeof(buf)); + if(n != 0){ + printf("bbb fd2=%d\n", fd2); + printf("%s: read %d bytes, wanted 0\n", s, n); + exit(1); + } + + write(fd1, "abcdef", 6); + + n = read(fd3, buf, sizeof(buf)); + if(n != 6){ + printf("%s: read %d bytes, wanted 6\n", s, n); + exit(1); + } + + n = read(fd2, buf, sizeof(buf)); + if(n != 2){ + printf("%s: read %d bytes, wanted 2\n", s, n); + exit(1); + } + + unlink("truncfile"); + + close(fd1); + close(fd2); + close(fd3); +} + +// write to an open FD whose file has just been truncated. +// this causes a write at an offset beyond the end of the file. +// such writes fail on xv6 (unlike POSIX) but at least +// they don't crash. +void +truncate2(char *s) +{ + unlink("truncfile"); + + int fd1 = open("truncfile", O_CREATE|O_TRUNC|O_WRONLY); + write(fd1, "abcd", 4); + + int fd2 = open("truncfile", O_TRUNC|O_WRONLY); + + int n = write(fd1, "x", 1); + if(n != -1){ + printf("%s: write returned %d, expected -1\n", s, n); + exit(1); + } + + unlink("truncfile"); + close(fd1); + close(fd2); +} + +void +truncate3(char *s) +{ + int pid, xstatus; + + close(open("truncfile", O_CREATE|O_TRUNC|O_WRONLY)); + + pid = fork(); + if(pid < 0){ + printf("%s: fork failed\n", s); + exit(1); + } + + if(pid == 0){ + for(int i = 0; i < 100; i++){ + char buf[32]; + int fd = open("truncfile", O_WRONLY); + if(fd < 0){ + printf("%s: open failed\n", s); + exit(1); + } + int n = write(fd, "1234567890", 10); + if(n != 10){ + printf("%s: write got %d, expected 10\n", s, n); + exit(1); + } + close(fd); + fd = open("truncfile", O_RDONLY); + read(fd, buf, sizeof(buf)); + close(fd); + } + exit(0); + } + + for(int i = 0; i < 150; i++){ + int fd = open("truncfile", O_CREATE|O_WRONLY|O_TRUNC); + if(fd < 0){ + printf("%s: open failed\n", s); + exit(1); + } + int n = write(fd, "xxx", 3); + if(n != 3){ + printf("%s: write got %d, expected 3\n", s, n); + exit(1); + } + close(fd); + } + + wait(&xstatus); + unlink("truncfile"); + exit(xstatus); +} + + // does chdir() call iput(p->cwd) in a transaction? void iputtest(char *s) @@ -2169,6 +2304,9 @@ main(int argc, char *argv[]) void (*f)(char *); char *s; } tests[] = { + {truncate1, "truncate1"}, + {truncate2, "truncate2"}, + {truncate3, "truncate3"}, {reparent2, "reparent2"}, {pgbug, "pgbug" }, {sbrkbugs, "sbrkbugs" }, -- cgit v1.2.3 From 7f35d7a14efe56905d340a0e318f01c7c514320d Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Fri, 7 Aug 2020 05:32:48 -0400 Subject: modify each page in usertests countfree() get rid of static for walk() and freewalk() --- user/usertests.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'user') diff --git a/user/usertests.c b/user/usertests.c index f83a060..aefbc9f 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -2251,9 +2251,12 @@ countfree() int n = 0; while(1){ - if((uint64)sbrk(4096) == 0xffffffffffffffff){ + uint64 a = (uint64) sbrk(4096); + if(a == 0xffffffffffffffff){ break; } + // modify the memory to make sure it's really allocated. + *(char *)(a - 1) = 1; n += 1; } sbrk(-((uint64)sbrk(0) - sz0)); -- cgit v1.2.3 From a93321cb2547dbb48bf8ce9ad623ac19eefbecea Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Fri, 7 Aug 2020 14:34:39 -0400 Subject: test pointer checking in copyin, copyout, copyinstr --- user/usertests.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) (limited to 'user') diff --git a/user/usertests.c b/user/usertests.c index aefbc9f..bdf6970 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -22,6 +22,92 @@ char buf[BUFSZ]; char name[3]; +void +copyin1(char *s) +{ + int fd = open("copyin1", O_CREATE|O_WRONLY); + if(fd < 0){ + printf("open(copyin1) failed\n"); + exit(1); + } + int n = write(fd, (void*)0x80000000LL, 8192); + if(n >= 0){ + printf("write(fd, 0x80000000LL, 8192) did not fail!\n"); + exit(1); + } + close(fd); + unlink("copyin1"); +} + +void +copyin2(char *s) +{ + int fd = open("copyin2", O_CREATE|O_WRONLY); + if(fd < 0){ + printf("open(copyin2) failed\n"); + exit(1); + } + int n = write(fd, (void*)0xffffffffffffffffLL, 8192); + if(n >= 0){ + printf("write(fd, 0xffffffffffffffffLL, 8192) did not fail!\n"); + exit(1); + } + close(fd); + unlink("copyin2"); +} + +void +copyout1(char *s) +{ + int fd = open("README", 0); + if(fd < 0){ + printf("open(README) failed\n"); + exit(1); + } + int n = read(fd, (void*)0x80000000LL, 8192); + if(n >= 0){ + printf("read(fd, 0x80000000LL, 8192) returned %d, not -1\n", n); + exit(1); + } + close(fd); +} + +void +copyout2(char *s) +{ + int fd = open("README", 0); + if(fd < 0){ + printf("open(README) failed\n"); + exit(1); + } + int n = read(fd, (void*)0xffffffffffffffffLL, 8192); + if(n >= 0){ + printf("read(fd, 0xffffffffffffffff, 8192) returned %d, not -1\n", n); + exit(1); + } + close(fd); +} + +void +copyinstr1(char *s) +{ + int fd = open((char *)0x80000000LL, O_CREATE|O_WRONLY); + if(fd >= 0){ + printf("open(0x80000000) returned %d, not -1\n", fd); + exit(1); + } +} + +void +copyinstr2(char *s) +{ + int fd = open((char *)0xffffffffffffffff, O_CREATE|O_WRONLY); + if(fd >= 0){ + printf("open(0xffffffffffffffff) returned %d, not -1\n", fd); + exit(1); + } +} + // test O_TRUNC. void truncate1(char *s) @@ -2307,6 +2393,12 @@ main(int argc, char *argv[]) void (*f)(char *); char *s; } tests[] = { + {copyin1, "copyin1"}, + {copyin2, "copyin2"}, + {copyout1, "copyout1"}, + {copyout2, "copyout2"}, + {copyinstr1, "copyinstr1"}, + {copyinstr2, "copyinstr2"}, {truncate1, "truncate1"}, {truncate2, "truncate2"}, {truncate3, "truncate3"}, -- cgit v1.2.3 From e3b7058907dff779cf94e23bf6bb84245faf481d Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Fri, 7 Aug 2020 15:06:43 -0400 Subject: streamline copyin/copyout code in usertests fix bugs in read/write return values when there's an error --- user/usertests.c | 157 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 83 insertions(+), 74 deletions(-) (limited to 'user') diff --git a/user/usertests.c b/user/usertests.c index bdf6970..8eb4aab 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -23,88 +23,100 @@ char buf[BUFSZ]; char name[3]; void -copyin1(char *s) +copyin(char *s) { - int fd = open("copyin1", O_CREATE|O_WRONLY); - if(fd < 0){ - printf("open(copyin1) failed\n"); - exit(1); - } - int n = write(fd, (void*)0x80000000LL, 8192); - if(n >= 0){ - printf("write(fd, 0x80000000LL, 8192) did not fail!\n"); - exit(1); - } - close(fd); - unlink("copyin1"); -} + uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff }; -void -copyin2(char *s) -{ - int fd = open("copyin2", O_CREATE|O_WRONLY); - if(fd < 0){ - printf("open(copyin2) failed\n"); - exit(1); - } - int n = write(fd, (void*)0xffffffffffffffffLL, 8192); - if(n >= 0){ - printf("write(fd, 0xffffffffffffffffLL, 8192) did not fail!\n"); - exit(1); + for(int ai = 0; ai < 2; ai++){ + uint64 addr = addrs[ai]; + + int fd = open("copyin1", O_CREATE|O_WRONLY); + if(fd < 0){ + printf("open(copyin1) failed\n"); + exit(1); + } + int n = write(fd, (void*)addr, 8192); + if(n >= 0){ + printf("write(fd, %p, 8192) returned %d, not -1\n", addr, n); + exit(1); + } + close(fd); + unlink("copyin1"); + + n = write(1, (char*)addr, 8192); + if(n > 0){ + printf("write(1, %p, 8192) returned %d, not -1 or 0\n", addr, n); + exit(1); + } + + int fds[2]; + if(pipe(fds) < 0){ + printf("pipe() failed\n"); + exit(1); + } + n = write(fds[1], (char*)addr, 8192); + if(n > 0){ + printf("write(pipe, %p, 8192) returned %d, not -1 or 0\n", addr, n); + exit(1); + } + close(fds[0]); + close(fds[1]); } - close(fd); - unlink("copyin2"); } void -copyout1(char *s) +copyout(char *s) { - int fd = open("README", 0); - if(fd < 0){ - printf("open(README) failed\n"); - exit(1); - } - int n = read(fd, (void*)0x80000000LL, 8192); - if(n >= 0){ - printf("read(fd, 0x80000000LL, 8192) returned %d, not -1\n", n); - exit(1); - } - close(fd); -} + uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff }; -void -copyout2(char *s) -{ - int fd = open("README", 0); - if(fd < 0){ - printf("open(README) failed\n"); - exit(1); - } - int n = read(fd, (void*)0xffffffffffffffffLL, 8192); - if(n >= 0){ - printf("read(fd, 0xffffffffffffffff, 8192) returned %d, not -1\n", n); - exit(1); - } - close(fd); -} + for(int ai = 0; ai < 2; ai++){ + uint64 addr = addrs[ai]; -void -copyinstr1(char *s) -{ - int fd = open((char *)0x80000000LL, O_CREATE|O_WRONLY); - if(fd >= 0){ - printf("open(0x80000000) returned %d, not -1\n", fd); - exit(1); + int fd = open("README", 0); + if(fd < 0){ + printf("open(README) failed\n"); + exit(1); + } + int n = read(fd, (void*)addr, 8192); + if(n > 0){ + printf("read(fd, %p, 8192) returned %d, not -1 or 0\n", addr, n); + exit(1); + } + close(fd); + + int fds[2]; + if(pipe(fds) < 0){ + printf("pipe() failed\n"); + exit(1); + } + n = write(fds[1], "x", 1); + if(n != 1){ + printf("pipe write failed\n"); + exit(1); + } + n = read(fds[0], (void*)addr, 8192); + if(n > 0){ + printf("read(pipe, %p, 8192) returned %d, not -1 or 0\n", addr, n); + exit(1); + } + close(fds[0]); + close(fds[1]); } } void -copyinstr2(char *s) +copyinstr(char *s) { - int fd = open((char *)0xffffffffffffffff, O_CREATE|O_WRONLY); - if(fd >= 0){ - printf("open(0xffffffffffffffff) returned %d, not -1\n", fd); - exit(1); + uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff }; + + for(int ai = 0; ai < 2; ai++){ + uint64 addr = addrs[ai]; + + int fd = open((char *)addr, O_CREATE|O_WRONLY); + if(fd >= 0){ + printf("open(%p) returned %d, not -1\n", addr, fd); + exit(1); + } } } @@ -2393,12 +2405,9 @@ main(int argc, char *argv[]) void (*f)(char *); char *s; } tests[] = { - {copyin1, "copyin1"}, - {copyin2, "copyin2"}, - {copyout1, "copyout1"}, - {copyout2, "copyout2"}, - {copyinstr1, "copyinstr1"}, - {copyinstr2, "copyinstr2"}, + {copyin, "copyin"}, + {copyout, "copyout"}, + {copyinstr, "copyinstr"}, {truncate1, "truncate1"}, {truncate2, "truncate2"}, {truncate3, "truncate3"}, -- cgit v1.2.3 From 76d6c57edec14071156e7780f7e8e08c200cf166 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Fri, 7 Aug 2020 16:39:56 -0400 Subject: test copyinstr()'s handling of the terminating null --- user/usertests.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) (limited to 'user') diff --git a/user/usertests.c b/user/usertests.c index 8eb4aab..5c2fc02 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -105,7 +105,7 @@ copyout(char *s) } void -copyinstr(char *s) +copyinstr1(char *s) { uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff }; @@ -120,6 +120,67 @@ copyinstr(char *s) } } +void +copyinstr2(char *s) +{ + char b[MAXPATH+1]; + + for(int i = 0; i < MAXPATH; i++) + b[i] = 'x'; + b[MAXPATH] = '\0'; + + int ret = unlink(b); + if(ret != -1){ + printf("unlink(%s) returned %d, not -1\n", b, ret); + exit(1); + } + + int fd = open(b, O_CREATE | O_WRONLY); + if(fd != -1){ + printf("open(%s) returned %d, not -1\n", b, fd); + exit(1); + } + + ret = link(b, b); + if(ret != -1){ + printf("link(%s, %s) returned %d, not -1\n", b, b, ret); + exit(1); + } + + char *args[] = { "xx", 0 }; + ret = exec(b, args); + if(ret != -1){ + printf("exec(%s) returned %d, not -1\n", b, fd); + exit(1); + } + + int pid = fork(); + if(pid < 0){ + printf("fork failed\n"); + exit(1); + } + if(pid == 0){ + static char big[PGSIZE+1]; + for(int i = 0; i < PGSIZE; i++) + big[i] = 'x'; + big[PGSIZE] = '\0'; + char *args2[] = { big, big, big, 0 }; + ret = exec("echo", args2); + if(ret != -1){ + printf("exec(echo, BIG) returned %d, not -1\n", fd); + exit(1); + } + exit(747); // OK + } + + int st = 0; + wait(&st); + if(st != 747){ + printf("exec(echo, BIG) succeeded, should have failed\n"); + exit(1); + } +} + // test O_TRUNC. void truncate1(char *s) @@ -2407,7 +2468,8 @@ main(int argc, char *argv[]) } tests[] = { {copyin, "copyin"}, {copyout, "copyout"}, - {copyinstr, "copyinstr"}, + {copyinstr1, "copyinstr1"}, + {copyinstr2, "copyinstr2"}, {truncate1, "truncate1"}, {truncate2, "truncate2"}, {truncate3, "truncate3"}, -- cgit v1.2.3 From d8fe1773b26758c7c7b8f36724cd822555b33612 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Fri, 7 Aug 2020 16:56:00 -0400 Subject: test string system call arguments that cross over the end of the last page. --- user/usertests.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'user') diff --git a/user/usertests.c b/user/usertests.c index 5c2fc02..dfe0039 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -22,6 +22,8 @@ char buf[BUFSZ]; char name[3]; +// what if you pass ridiculous pointers to system calls +// that read user memory with copyin? void copyin(char *s) { @@ -64,6 +66,8 @@ copyin(char *s) } } +// what if you pass ridiculous pointers to system calls +// that write user memory with copyout? void copyout(char *s) { @@ -104,6 +108,7 @@ copyout(char *s) } } +// what if you pass ridiculous string pointers to system calls? void copyinstr1(char *s) { @@ -120,6 +125,9 @@ copyinstr1(char *s) } } +// what if a string system call argument is exactly the size +// of the kernel buffer it is copied into, so that the null +// would fall just beyond the end of the kernel buffer? void copyinstr2(char *s) { @@ -181,6 +189,50 @@ copyinstr2(char *s) } } +// what if a string argument crosses over the end of last user page? +void +copyinstr3(char *s) +{ + sbrk(8192); + uint64 top = (uint64) sbrk(0); + if((top % PGSIZE) != 0){ + sbrk(PGSIZE - (top % PGSIZE)); + } + top = (uint64) sbrk(0); + if(top % PGSIZE){ + printf("oops\n"); + exit(1); + } + + char *b = (char *) (top - 1); + *b = 'x'; + + int ret = unlink(b); + if(ret != -1){ + printf("unlink(%s) returned %d, not -1\n", b, ret); + exit(1); + } + + int fd = open(b, O_CREATE | O_WRONLY); + if(fd != -1){ + printf("open(%s) returned %d, not -1\n", b, fd); + exit(1); + } + + ret = link(b, b); + if(ret != -1){ + printf("link(%s, %s) returned %d, not -1\n", b, b, ret); + exit(1); + } + + char *args[] = { "xx", 0 }; + ret = exec(b, args); + if(ret != -1){ + printf("exec(%s) returned %d, not -1\n", b, fd); + exit(1); + } +} + // test O_TRUNC. void truncate1(char *s) @@ -2470,6 +2522,7 @@ main(int argc, char *argv[]) {copyout, "copyout"}, {copyinstr1, "copyinstr1"}, {copyinstr2, "copyinstr2"}, + {copyinstr3, "copyinstr3"}, {truncate1, "truncate1"}, {truncate2, "truncate2"}, {truncate3, "truncate3"}, -- cgit v1.2.3