Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the initial call to sbrk(0) in Linux always return a value aligned to 8 bytes ( or 4 in case of 32-bit systems)

Tags:

c

linux

gcc

I was looking into the implementation of malloc defined here:

http://www.inf.udec.cl/~leo/Malloc_tutorial.pdf.

The author create a metadata structure that is naturally aligned on a 4 byte boundary and then aligns a request for x bytes to a 4 byte boundary after the metadata structure which effectively acts as a header for the block. The pdf states that since the metadata and the request are now aligned , the resultant data will be completely aligned. The result works out if the first call to sbrk() returns a base address for the heap that is aligned to a 4-byte boundary. Does sbrk() always return a 4 byte (or 8 byte in case of 64-bit systems) aligned address in the initial call ?

like image 976
draklor40 Avatar asked Dec 07 '14 07:12

draklor40


1 Answers

The standard for brk and sbrk explicitly does not specify whether the returned address is aligned in any way. On Mac OS X (and maybe other BSD systems) the sizes/addresses are page-aligned, but on Linux no such rounding takes place as can easily be tested with this little program:

#include <unistd.h>
#include <stdio.h>

int main() {
        void *p;
        p = sbrk(0);
        printf("Initial brk: %p\n", p);
        p = sbrk(1); // Increase the brk (returns OLD brk!)
        p = sbrk(0); // Get the new brk
        printf("New brk: %p\n", p);

        return 0;
}

On one of my systems, the output was:

Initial brk: 0x602000
New brk: 0x602001

But you asked for the initial call. The Linux man-page states:

brk() and sbrk() change the location of the program break, which defines the end of the process's data segment (i.e., the program break is the first location after the end of the uninitialized data segment). Increasing the program break has the effect of allocating memory to the process; decreasing the break deallocates memory.

The unitialized data segment is also known as BSS. The keyword here is segment, so it's very likely the initial value is always page-aligned.

If you want to be on the safe side and check, you can verify the initial address by taking the modulo with the page size (which you can query via getpagesize).


Update: So I was curious and dug around a bit more. In the man-page, I already read that brk and sbrk are implemented atop the kernel's sys_brk. Its implementation in the kernel source can be found in mm/mmap.c (or mm/nommu.c for systems without a Memory Management Unit; we'll ignore this one). In the brk implementation in mm/mmap.c, we find this line:

newbrk = PAGE_ALIGN(brk);

("brk" here is the argument, not the function.) So the kernel does do page aligning… sort of: while the calculations are done with the page-aligned values and any necessary memory allocation is page-aligned, the value stored for the brk is actually the pointer value you passed:

mm->brk = brk;

So in the user-space it doesn't look like any page-algning took place even though the kernel did. I looked at versions 3.17.5 and 2.4.37, the behaviour is the same.

Regarding the initial value, in fs/binfmt_elf.c (which implements ELF linking) we find a function set_brk which sets the initial "brk" value (mm->start_brk). This value is explicitly page-aligned. The same is true for fs/binfmt_aout.c which handles the old a.out format and fs/binfmt_som.c which handles HP-UX SOM format (never heard of it before). There's also fs/binfmt_flat.c which sets the initial brk value but doesn't align explicitly; the value is implicitly aligned here. So it looks like the initial value is always page-aligned. At least it's guaranteed to be page-aligned for ELF files, which is what we care about for "normal" systems.

The glibc simply wraps sys_brk and adds bookkeeping to correctly implement sbrk. So glibc's brk behaviour is that of the kernel, the return value sys_brk is stored in an internal hidden variable __curbrk so that sbrk can calculate the new address correctly.

like image 81
DarkDust Avatar answered Nov 05 '22 05:11

DarkDust