I've heard in a lot of places (musl mailing list, macOS forums, etc.) that brk()
and sbrk()
are unsafe. Many of these places either don't give explanations at all, or give very vague explanations. For example, this link states that "these functions are fundamentally broken", and goes on to say that the malloc
and sbrk
subsystems are utterly broken, that they ruin the heap, et al.
My question is: Why is this so? If malloc
is used in such a way that it allocates a block of memory with sbrk
large enough to quell or substantially decrease the need for further allocations, then shouldn't sbrk
and brk
be perfectly safe to use?
Here are my implementations of sbrk
and brk
:
sbrk
:
#include <unistd.h>
#include <stddef.h>
void *sbrk(intptr_t inc)
{
intptr_t curbrk = syscall(SYS_brk, NULL);
if( inc == 0 ) goto ret;
if( curbrk < 0 ) return (void *)-1;
curbrk((void *)(curbrk+inc));
ret:
return (void *)curbrk;
}
brk
:
#include <unistd.h>
intptr_t brk(void *ptr)
{
if( (void *)syscall(SYS_brk, ptr) != ptr )
return -1;
else
return 0;
}
For an application to use them correctly, it must depend on the malloc subsystem never being used, but this is impossible to guarantee since malloc may be used internally by libc functions without documenting this to the application.
. If your app calls sbrk and your app calls malloc and malloc calls sbrk and sbrk function uses global context, the result will be a mess. They want to eliminate the sbrk function, to make users not use it, not because it is a bad design per se. – Gerdagerdeensbrk
usually operates on a single global variable, ex__curbrk
in glibc orstatic char *heap_end;
in newlib. That means that all "contexts" (threads, functions, malloc, printf and user app) share the same ("global" to the process) data segment. – Gerdagerdeensyscall(SYS_brk, 0)
. – Freemalloc
implementations are written to assume that nobody else is callingsbrk
behind their back. For instance, suppose you callp = malloc(N)
where N is some large number (maybe a multiple of page size). malloc doessbrk(N)
to get memory from the OS and returns this pointer to you. Later (without any intervening calls to malloc) you dofree(p)
. Now malloc "knows" that it can dosbrk(-N)
to return the memory to the OS. If you have calledsbrk
in between, then you have a problem. – Resolutesbrk
a multiple ofN
and then implement afree(...)
which only marks the memory as available for other uses. You really have a lot of control when you write a standard C library from scratch :). – Freesbrk
screwing anything up, becausemalloc
's memory has already been allocated. – Freefree
d memory could be cleaned up and deallocated. – Freebrk/sbrk
(intro level only) – Stoneham