2

I am trying to implement understand how dynamic memory allocation is happening. So I thought of implementing malloc of my own using sbrk() system call. My Question here is when i try to allocate dynamic memory, sbrk() and malloc() returns different addresses not continuous.

Here is my code

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    printf("\nsbrk(0) %llu ",(unsigned long long)sbrk(0));
    printf("\nmalloc(8) %llu ",(unsigned long long)malloc(8));
    printf("\nmalloc(8) %llu ",(unsigned long long)malloc(8));
    printf("\nsbrk(8) %llu ",(unsigned long long)sbrk(8));
    printf("\nmalloc(8) %llu ",(unsigned long long)malloc(8));
    printf("\nmalloc(8) %llu ",(unsigned long long)malloc(8));  
    printf("\n");
    return 0;
}

Output of the above code is

sbrk(0) 30306304 
malloc(8) 30306320 
malloc(8) 30306352 
sbrk(8) 30441472 
malloc(8) 30306384 
malloc(8) 30306416 

Can anyone explain why sbrk(8) is not continuous locations.

E_net4
  • 27,810
  • 13
  • 101
  • 139

2 Answers2

4

Assuming you're running on Linux, the reason the memory from malloc() and sbrk() has a relative large difference in location is that the glibc malloc() implementation uses sbrk() internally to obtain the memory that functions such as malloc() return to the caller. For example, assume the initial internal glibc implementation obtains 32 MB of heap memory via sbrk() and memory returned from malloc() will be in this 32 MB chunk. If you then use sbrk() to obtain memory, it will be from memory newly allocate at the end of that original 32 MB chunk, so the addresses from malloc() and sbrk() will differ.

Note that you can't safely mix the use of malloc() (and calloc(), realloc(), etc) and sbrk() since the internal implementation of malloc() uses sbrk() to obtain the memory it returns via malloc(). Per the Linux malloc() man page:

Normally, malloc() allocates memory from the heap, and adjusts the size of the heap as required, using sbrk(2). When allocating blocks of memory larger than MMAP_THRESHOLD bytes, the glibc malloc() implementation allocates the memory as a private anonymous mapping using mmap(2). MMAP_THRESHOLD is 128 kB by default, but is adjustable using mallopt(3). Prior to Linux 4.7 allocations performed using mmap(2) were unaffected by the RLIMIT_DATA resource limit; since Linux 4.7, this limit is also enforced for allocations performed using mmap(2).

When you mix malloc() and sbrk() on Linux to obtain memory, you will likely corrupt the process's heap.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
2

The standard does not give any guarantee for the contiguity of storage even for memory allocated by successive calls to malloc. So the different calls to malloc in your code need not yield contiguous locations.

The C11 standard states:

7.22.3 Memory management functions

1. The order and contiguity of storage allocated by successive calls to the aligned_alloc, calloc, malloc, and realloc functions is unspecified.

And the addresses that come from the mixing up of malloc and sbrk calls need not be contiguous either.

P.W
  • 26,289
  • 6
  • 39
  • 76