4
votes

I am making some example stack and heap allocation on an Ubuntu 14.04 VM (Linux 3.13.0-55-generic i686) and I am confused by the memory addresses for the heap allocations.

The below C code allocates three 32-bit unsigned ints on the stack and three allocation on the heap of diminishing sizes, 32 bits, 16 bits and finally 8 bits.

In the output below we can see that the memory addresses for the three 32 bit ints on the stack are 4 bits apart. uint32_t i is at 0xbffd4818 and 4 addresses later at 0xbffd481c is uint32_t j. So we can see here that each individual byte of memory is addressable and so each 4 byte memory block is 4 memory addresses apart.

Looking at the heap allocations though we can see that uint32_t i_ptr points to 0x99ae008 and malloc requested 4 bytes of space, so I would expect uint16_t j_ptr to start at 0x99ae00c but it starts at 0x99ae018. The third heap allocation for uint8_t k_ptr starts 16 bytes after uint16_t i_ptr which also starts 16 bytes after uint32_t i_ptr.

  1. Is it just a default OS setting that each heap allocation is 16 bytes apart?
  2. Why is this happening irrelevant of the size I passed to malloc?
  3. How can we fit 4 bytes of information between 0x99ae008 and 0x99ae018?

C Source:

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

int main () {

    register uint32_t ebp asm ("ebp");
    printf("0x%x\n", ebp);

    register uint32_t esp asm ("esp");
    printf("0x%x\n", esp);

    uint32_t i;
    printf("%p\n", &i);

    uint32_t j;
    printf("%p\n", &j);

    uint32_t k;
    printf("%p\n", &k);

    uint32_t *i_ptr = malloc(4);
    printf("%p\n", i_ptr);

    uint16_t *j_ptr = malloc(2);
    printf("%p\n", j_ptr);

    uint8_t *k_ptr = malloc(1);
    printf("%p\n", k_ptr);

    free(i_ptr);
    free(j_ptr);
    free(k_ptr);

    return 0;

}

CLI output:

$ gcc -o heap2 heap2.c
$ ./heap2
0xbffd4838  // EBP
0xbffd4800  // ESP
0xbffd4818  // uint32_t i
0xbffd481c  // uint32_t j
0xbffd4820  // uint32_t k
0x99ae008   // uint32_t i_ptr
0x99ae018   // uint16_t j_ptr
0x99ae028   // uint8_t  k_ptr
1

1 Answers

2
votes

malloc returns a pointer of type void * that may be casted to a pointer of any other type. So malloc provides alignment that satisfies the requirement of any type.

Usually malloc returns an address that is aligned by the paragraph (in most systems it is equal to 16 bytes). And moreover malloc allocates extents that also have minimal size of the paragraph. So if you will write for example

char *p = malloc( 1 );

then in fact malloc reserves an extent of 16 bytes.