diff --git a/kernel/proc.c b/kernel/proc.c index 786e5c3..0d91a59 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -232,9 +232,7 @@ growproc(int n) return -1; } } else if(n < 0){ - if((sz = uvmdealloc(p->pagetable, sz, sz + n)) == 0) { - return -1; - } + sz = uvmdealloc(p->pagetable, sz, sz + n); } p->sz = sz; return 0; diff --git a/kernel/vm.c b/kernel/vm.c index 51165b7..8036be7 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -268,7 +268,10 @@ uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) { if(newsz >= oldsz) return oldsz; - uvmunmap(pagetable, newsz, oldsz - newsz, 1); + + uint64 newup = PGROUNDUP(newsz); + uvmunmap(pagetable, newup, oldsz - newup, 1); + return newsz; } diff --git a/user/usertests.c b/user/usertests.c index 22b01a2..0f4a443 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -1923,6 +1923,45 @@ pgbug(char *s) exit(0); } +// does the kernel panic if a process sbrk()s its size to be less than +// a page, or zero? +void +zerosize(char *s) +{ + int pid = fork(); + if(pid < 0){ + printf("fork failed\n"); + exit(1); + } + if(pid == 0){ + int sz = (uint64) sbrk(0); + // free all user memory; there used to be a bug that + // would not adjust p->sz correctly in this case, + // causing exit() to panic. + sbrk(-sz); + // user page fault here. + exit(0); + } + wait(0); + + pid = fork(); + if(pid < 0){ + printf("fork failed\n"); + exit(1); + } + if(pid == 0){ + int sz = (uint64) sbrk(0); + // set the break to somewhere in the very first + // page; there used to be a bug that would incorrectly + // free the first page. + sbrk(-(sz - 3500)); + exit(0); + } + wait(0); + + exit(0); +} + // run each test in its own process. run returns 1 if child's exit() // indicates success. int @@ -1961,6 +2000,7 @@ main(int argc, char *argv[]) char *s; } tests[] = { {pgbug, "pgbug" }, + {zerosize, "zerosize" }, {reparent, "reparent" }, {twochildren, "twochildren"}, {forkfork, "forkfork"},