From c5ce605da0b6e5991742cf4bd4a717f13db05a1a Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Sat, 7 Dec 2024 17:49:29 -0700 Subject: [PATCH] [kernel,libc] Rewrite kernel brk/sbrk, fix C library malloc --- elks/arch/i86/kernel/process.c | 34 +++++++++++------------ elks/arch/i86/mm/malloc.c | 49 +++++++++++++++++++++------------- libc/malloc/Makefile | 9 ++++--- libc/malloc/__mini_malloc.c | 8 +++--- libc/malloc/malloc.c | 6 ++++- 5 files changed, 63 insertions(+), 43 deletions(-) diff --git a/elks/arch/i86/kernel/process.c b/elks/arch/i86/kernel/process.c index d50a2c9bc..95740bd4e 100644 --- a/elks/arch/i86/kernel/process.c +++ b/elks/arch/i86/kernel/process.c @@ -43,27 +43,27 @@ int run_init_process_sptr(const char *cmd, char *sptr, int slen) } /* - * We only need to do this as long as we support old format binaries - * that grow stack and heap towards each other + * Check that SP is within proper range, called before every syscall. */ void stack_check(void) { - segoff_t end = current->t_endbrk; - - { - /* optional: check stack over min stack*/ - if (current->t_regs.sp < current->t_begstack - current->t_minstack) { - if (current->t_minstack) /* display if protected stack*/ - printk("(%P)STACK OUTSIDE PROTECTED LIMIT by %u\n", - current->t_begstack - current->t_minstack - current->t_regs.sp); - } - - /* check stack overflow heap*/ - if (current->t_regs.sp > end) - return; + segoff_t sp = current->t_regs.sp; + segoff_t brk = current->t_endbrk; + segoff_t stacklow = current->t_begstack - current->t_minstack; + + if (sp < brk) { + printk("(%P)STACK OVERFLOW by %u\n", brk - sp); + printk("curbreak %u, SP %u\n", current->t_endbrk, current->t_regs.sp); + do_exit(SIGSEGV); + } + if (sp < stacklow) { + /* notification only, allow process to continue */ + printk("(%P)STACK USING %u UNUSED HEAP\n", stacklow - sp); + } + if (sp > current->t_begstack) { + printk("(%P)STACK UNDERFLOW\n"); + do_exit(SIGSEGV); } - printk("(%P)STACK OVERFLOW by %u\n", end - current->t_regs.sp); - do_exit(SIGSEGV); } /* diff --git a/elks/arch/i86/mm/malloc.c b/elks/arch/i86/mm/malloc.c index d8fea63ae..d14d56f8b 100644 --- a/elks/arch/i86/mm/malloc.c +++ b/elks/arch/i86/mm/malloc.c @@ -230,8 +230,11 @@ void mm_get_usage (unsigned int * pfree, unsigned int * pused) // User data segment functions -int sys_brk(segoff_t newbrk) +static int set_brk(segoff_t brk, int increment) { + segoff_t newbrk = brk + increment; + segoff_t stacklow; + /***unsigned int memfree, memused; mm_get_usage(&memfree, &memused); printk("brk(%P): new %x, edat %x, ebrk %x, free %x sp %x, eseg %x, %d/%dK\n", @@ -239,36 +242,46 @@ int sys_brk(segoff_t newbrk) current->t_regs.sp - current->t_endbrk, current->t_regs.sp, current->t_endseg, memfree, memused);***/ - if (newbrk < current->t_enddata) + if (newbrk < current->t_enddata) { + printk("(%P)SBRK %d FAIL, BELOW HEAP\n", increment); return -ENOMEM; + } - if (current->t_begstack > current->t_endbrk) { /* stack above heap?*/ - if (newbrk > current->t_begstack - current->t_minstack) { - printk("(%d)CAN'T EXPAND HEAP by %u\n", - current->pid, newbrk - (current->t_begstack - current->t_minstack)); - return -ENOMEM; - } + stacklow = current->t_begstack - current->t_minstack; + if (newbrk > stacklow) { + printk("(%P)SBRK %d FAIL, OUT OF HEAP SPACE\n", increment); + return -ENOMEM; + } + if (newbrk > current->t_regs.sp) { + printk("(%P)SBRK %d FAIL, WOULD OVERWRITE STACK\n", increment); + return -ENOMEM; } - current->t_endbrk = newbrk; + current->t_endbrk = newbrk; return 0; } +int sys_brk(segoff_t newbrk) +{ + dprintk("(%P)BRK %u\n", newbrk); + return set_brk(newbrk, 0); +} -int sys_sbrk (int increment, segoff_t *pbrk) +int sys_sbrk(int increment, segoff_t *pbrk) { segoff_t brk = current->t_endbrk; /* always return start of old break*/ int err; - debug("sbrk incr %u pointer %04x curbreak %04x\n", increment, pbrk, brk); + if (increment) + dprintk("(%P)SBRK %d, curbreak %u, SP %u\n", + increment, current->t_endbrk, current->t_regs.sp); err = verify_area(VERIFY_WRITE, pbrk, sizeof(*pbrk)); if (err) return err; - if (increment) { - err = sys_brk(brk + increment); - if (err) return err; - } - + /* FIXME test for brk+increment overflow/underflow here */ + err = set_brk(brk, increment); + if (err) + return err; put_user (brk, pbrk); return 0; } @@ -303,12 +316,12 @@ int sys_fmemfree(unsigned short segment) seg_free(seg); return 0; } - debug("sys_fmemfree: not owner %04x\n", segment); + printk("sys_fmemfree: not owner %04x\n", segment); return -EACCES; } n = seg->all.next; } - debug("sys_fmemfree: segment not found %04x\n", segment); + printk("sys_fmemfree: segment not found %04x\n", segment); return -EINVAL; } diff --git a/libc/malloc/Makefile b/libc/malloc/Makefile index d332c967a..1a85fae90 100644 --- a/libc/malloc/Makefile +++ b/libc/malloc/Makefile @@ -4,12 +4,13 @@ COMPILER ?= ia16 LIB ?= out.a include $(TOPDIR)/libc/$(COMPILER).inc -#CFLAGS += -DL_alloca -#CFLAGS += -DLAZY_FREE -# MCHUNK is word not byte min allocation size -CFLAGS += -DMCHUNK=512 +# allocations smaller than MCHUNK words (not bytes) are rounded up, +# larger requests are allocated from heap as is. +CFLAGS += -DMCHUNK=16 #CFLAGS += -DMINALLOC +#CFLAGS += -DLAZY_FREE #CFLAGS += -DVERBOSE +#CFLAGS += -DL_alloca # use V7 malloc for heap integrity checking #OBJS = v7malloc.o calloc.o sbrk.o brk.o diff --git a/libc/malloc/__mini_malloc.c b/libc/malloc/__mini_malloc.c index c6c1c0f1f..91b7b2e88 100644 --- a/libc/malloc/__mini_malloc.c +++ b/libc/malloc/__mini_malloc.c @@ -8,12 +8,16 @@ void __wcnear * __mini_malloc(size_t size) { mem __wcnear *ptr; - size_t sz; +#if 0 + size_t sz; /* First time round this _might_ be odd, But we won't do that! */ sz = (size_t)sbrk(0); if(sz & (sizeof(mem) - 1)) sbrk(4 - (sz & (sizeof(mem) - 1))); +#endif + + size += sizeof(mem) * 2 - 1; /* Round up and leave space for size field */ /* Minor oops here, sbrk has a signed argument */ if((int)size <= 0 || size > (((unsigned)-1) >> 1) - sizeof(mem) * 3) @@ -22,9 +26,7 @@ __mini_malloc(size_t size) return 0; } - size += sizeof(mem) * 2 - 1; /* Round up and leave space for size field */ size /= sizeof(mem); - ptr = (mem __wcnear *) sbrk(size * sizeof(mem)); /*if((uintptr_t)ptr == (intptr_t)-1)*/ /* this is better only when not __wcnear */ if ((int)ptr == -1) diff --git a/libc/malloc/malloc.c b/libc/malloc/malloc.c index cc7d31a1e..58a2dd2e4 100644 --- a/libc/malloc/malloc.c +++ b/libc/malloc/malloc.c @@ -265,10 +265,13 @@ malloc(size_t size) { #ifdef MCHUNK unsigned int alloc; - alloc = sizeof(mem) * (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1); + if (sz < MCHUNK) + alloc = sizeof(mem) * (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1); + else alloc = sz * sizeof(mem); ptr = __mini_malloc(alloc); if (ptr) __insert_chunk(ptr - 1); +#if MCHUNK >= 256 else /* Oooo, near end of RAM */ { unsigned int needed = alloc; @@ -283,6 +286,7 @@ malloc(size_t size) else alloc/=2; } } +#endif ptr = __search_chunk(sz); if (ptr == 0) #endif