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.
- Is it just a default OS setting that each heap allocation is 16 bytes apart?
- Why is this happening irrelevant of the size I passed to malloc?
- 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