scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

commit 648ccc16cf9179e23f9a90c41598d7ccbb2e4c88
parent bf6ef5c8f08b77bc3f2b0cca055524c29fa162bc
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue, 14 Sep 2021 14:19:07 +0200

libc: Fix malloc() in linux

Linux brk() syscall does not follow the SUSv2 behaviour.
SUSv2 mandates brk() to return an integer that indicates
if the syscall was correct or not, but Linux returns the
previous heap in case of error. Sbrk() in malloc.c   was
trying to solve that problem with a weird comparision,
that generated an integer to pointer conversion, because
the prototype of _brk() was returning integer but   the
actual syscall was returning a pointer, truncating the
value to 32 bits. This patch adds a wrapper over the Linux
syscall and ry to keep the portable code to the SUSv2
interface.

Diffstat:
Asrc/libc/arch/linux/Makefile | 12++++++++++++
Asrc/libc/arch/linux/_brk.c | 16++++++++++++++++
Msrc/libc/arch/linux/_getheap.c | 3++-
Asrc/libc/arch/linux/brk.h | 2++
Asrc/libc/arch/linux/deps.mk | 5+++++
Msrc/libc/stdlib/malloc.c | 4+---
6 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/src/libc/arch/linux/Makefile b/src/libc/arch/linux/Makefile @@ -0,0 +1,12 @@ +.POSIX: +PROJECTDIR = ../../../.. +include $(PROJECTDIR)/scripts/rules.mk +include ../../rules.mk + +OBJS=\ + _brk.$O\ + _getheap.$O\ + +all: $(OBJS) + +include deps.mk diff --git a/src/libc/arch/linux/_brk.c b/src/libc/arch/linux/_brk.c @@ -0,0 +1,16 @@ +#include <errno.h> +#include <stddef.h> + +#include "../../libc.h" +#include "../../syscall.h" +#include "brk.h" + +int +_brk(void *addr) +{ + if (_sys_brk(addr) != addr) { + errno = ENOMEM; + return -1; + } + return 0; +} diff --git a/src/libc/arch/linux/_getheap.c b/src/libc/arch/linux/_getheap.c @@ -2,9 +2,10 @@ #include "../../libc.h" #include "../../syscall.h" +#include "brk.h" void * _getheap(void) { - return _brk(0); + return _sys_brk(0); } diff --git a/src/libc/arch/linux/brk.h b/src/libc/arch/linux/brk.h @@ -0,0 +1,2 @@ +extern void *_sys_brk(void *); + diff --git a/src/libc/arch/linux/deps.mk b/src/libc/arch/linux/deps.mk @@ -0,0 +1,5 @@ +#deps +./_brk.o: ./../../libc.h +./_brk.o: ./../../syscall.h +./_getheap.o: ./../../libc.h +./_getheap.o: ./../../syscall.h diff --git a/src/libc/stdlib/malloc.c b/src/libc/stdlib/malloc.c @@ -75,7 +75,6 @@ static void * sbrk(uintptr_t inc) { char *new, *old; - void *p; static void *heap; if (!heap) @@ -86,8 +85,7 @@ sbrk(uintptr_t inc) return ERRADDR; new = old + inc; - p = _brk(new); - if (p == old || p == ERRADDR) + if (_brk(new) < 0) return ERRADDR; heap = new;