2

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?

aboria
  • 123
  • 6
  • (Your printfs are wrong; `new2pb` isn't an `int`.) [Fixed demo](https://wandbox.org/permlink/cstMFRl8F2e29VT3) – Kerrek SB Jan 27 '19 at 22:47
  • hmmm, then what is it ? – aboria Jan 27 '19 at 22:48
  • 1
    Errr... a `void *`? It's your variable, you should know, you made it! :-) You need the `%p` format specifier, or otherwise cast the pointer to an appropriate integral type (e.g. `uintptr_t`) and use an appropriate specifier. But `%p` should be just fine to demonstrate the situation nicely. (Nice question, by the way.) – Kerrek SB Jan 27 '19 at 22:51
  • Yeppers, that makes sense, ok I used %p and it returned the address, i will edit my question – aboria Jan 27 '19 at 22:52
  • 1
    Never a dupe for such a specific question has been so exact. Indeed, when I saw this question I thought that it was that old one that got bumped up for some reason. – Matteo Italia Jan 27 '19 at 23:22

1 Answers1

3

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
Craig Estey
  • 30,627
  • 4
  • 24
  • 48