17

I'm trying to understand the sbrk() function.

From what I know:
sbrk(0) returns the current address of the break and doesn't increment it.
sbrk(size) increments the address of the break by size bytes and returns the previous address of the break.

So I created something to test it:

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

int main(void)
{
    printf("sbrk(0) = %p\n", sbrk(0)); // should return value x
    printf("sbrk(0) = %p\n", sbrk(0)); // should return value x
    printf("sbrk(5) = %p\n", sbrk(5)); // should return value x
    printf("sbrk(0) = %p\n", sbrk(0)); // should return value x + 5
}

So I'm expecting to see a result looking like this:

sbrk(0) = 0x1677000 // x value
sbrk(0) = 0x1677000 // x value
sbrk(5) = 0x1677000 // x value
sbrk(0) = 0x1677005 // x value + 5

but instead I'm getting this:

sbrk(0) = 0x1677000 // x value
sbrk(0) = 0x1698000 // y value
sbrk(5) = 0x1698000 // y value
sbrk(0) = 0x1698005 // y value + 5

Why don't the first two calls of sbrk(0) return the same value? What happens between those two calls that changes the break address?

EDIT : Storing addresses in variables solves the problem:

int main(void)
{
    void *toto1 = sbrk(0);
    void *toto2 = sbrk(0);
    void *toto3 = sbrk(5);
    void *toto4 = sbrk(0);

    printf("sbrk(0) = %p\n", toto1);
    printf("sbrk(0) = %p\n", toto2);
    printf("sbrk(5) = %p\n", toto3);
    printf("sbrk(0) = %p\n", toto4);
}

Boann
  • 48,794
  • 16
  • 117
  • 146
Bibas
  • 498
  • 1
  • 4
  • 17
  • 13
    `printf` might use some dynamic memory stuff. Try assigning the values to variables instead and print them at once. – Eugene Sh. Jan 21 '19 at 17:09
  • I tried it just now, it doesn't change anything, the printf doesn't have an influence on that apparently. – Bibas Jan 21 '19 at 17:19
  • 1
    Then please update your question with the other code as well, so no one will repeat this assumption. – Eugene Sh. Jan 21 '19 at 17:24
  • 3
    You need to use *multiple* variables, and do *all* calls to `sbrk` before calling `printf`. Your updated code does basically just the same as the first and will have the same problem. – Some programmer dude Jan 21 '19 at 17:32
  • Maybe use this checklist:https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/ – Yunnosch Jan 21 '19 at 17:32
  • The updated code does not eliminate the possibility I was talking about. You are still interleaving it with `printf`s – Eugene Sh. Jan 21 '19 at 17:32
  • Yes, that's my bad sorry, I tried it with variables for each call and it solves the problem. So it was basically because of the memory management done by printf ? And if so, why did it occurs only on the first 2 calls ? – Bibas Jan 21 '19 at 17:41
  • You will probably need to look at your specific `printf` implementation to find out. – Eugene Sh. Jan 21 '19 at 17:46
  • 1
    My *guess* is that the initialization of the standard I/O parts is done lazily. That is, the initialization is done when they are needed, and part of that initialization is allocation of the buffer for `stdout`. – Some programmer dude Jan 21 '19 at 17:50
  • 1
    Here is the argument handling code of glibc: https://github.com/bminor/glibc/blob/master/stdio-common/vfprintf-internal.c It calls `malloc()` in a few places. – rumpelsepp Jan 21 '19 at 17:50

1 Answers1

13

Your program performs the following sequence of calls:

sbrk()
printf()
sbrk()
printf()
...

The first call to printf calls malloc internally to allocate a buffer for stdout (stdout is line buffered by default, but the buffer is created on demand the first time you print to it).

That's why the second call to sbrk returns a different value.

(This answer is not directly related, but the error messages from valgrind expose the existence of the underlying malloc call hidden inside printf.)

Your second example performs all sbrk calls up front, so there are no surprises from other functions calling malloc behind your back.

melpomene
  • 84,125
  • 8
  • 85
  • 148