cmemorysbrkbrk

Why is the return value of the first sbrk different than subsequent calls?


I am trying to understand how memory works in C, so am experimenting with the sbrk function now. I know that sbrk(0) should return the current program break, that is the end of the data segment.

So I tried to call sbrk(0) multiple times and for some reason I get the first value different than the other values. For example, this program

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

int main()
{
        void * currpb = sbrk(0);
        printf("The current program break is: %p.\n", currpb);

        void * newpb = sbrk(0);
        printf("The current program break is: %p.\n", newpb);

        void *new2pb = sbrk(0);
        printf("The current program break is: %p.\n", new2pb);

        void *new3pb = sbrk(0);
        printf("The current program break is: %p.\n", new3pb);
}

Give me the following output:

The current program break is: 0x18b0000.
The current program break is: 0x18d1000.
The current program break is: 0x18d1000.
The current program break is: 0x18d1000.

Am not sure why the 1st value is different than the other three values, any ideas?


Solution

  • When you do printf, it is calling/using malloc, which will do its own calls to sbrk/brk to allocate some space and add it to the memory heap/pool.

    The first one has to allocate some space, so the sbrk value goes up. The subsequent ones can reuse that space, so they don't do their own sbrk again. But, they now have the sbrk value that has been perturbed by the first printf call.

    If you use write and save the output to a file and examine it with a hex editor, you don't have the same problem. All values are the same:

    #include <stdio.h>
    #include <unistd.h>
    
    int
    main()
    {
        void *pb;
    
        pb = sbrk(0);
        write(1,&pb,sizeof(pb));
    
        pb = sbrk(0);
        write(1,&pb,sizeof(pb));
    
        pb = sbrk(0);
        write(1,&pb,sizeof(pb));
    
        pb = sbrk(0);
        write(1,&pb,sizeof(pb));
    
        return 0;
    }
    

    Here is the hex output:

    00000000: 00908401 00000000 00908401 00000000  ................
    00000010: 00908401 00000000 00908401 00000000  ................
    

    Another [simpler] way to see this is to do all sbrk calls without the intervening printf:

    #include <stdio.h>
    #include <unistd.h>
    
    int
    main()
    {
        void *pb[4];
    
        for (int idx = 0;  idx < 4;  ++idx)
            pb[idx] = sbrk(0);
    
        for (int idx = 0;  idx < 4;  ++idx)
            printf("pb=%p sbrk=%p\n",pb[idx],sbrk(0));
    
        return 0;
    }
    

    The output of this is:

    pb=0xc42000 sbrk=0xc42000
    pb=0xc42000 sbrk=0xc63000
    pb=0xc42000 sbrk=0xc63000
    pb=0xc42000 sbrk=0xc63000