Why is function pointer 12 bytes long?

0

I've been inspecting the heap memory when executing the following code:

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>

struct data {
 char name[64];
};

struct fp {
 int (*fp)();
};

void winner()
{
 printf("level passed\n");
}

void nowinner()
{
  printf("level has not been passed\n");
}

int main(int argc, char **argv)
{
 struct data *d;
 struct fp *f;

 d = malloc(sizeof(struct data));
 f = malloc(sizeof(struct fp));
 f->fp = nowinner;

 printf("data is at %p, fp is at %p\n", d, f);

 strcpy(d->name, argv[1]);

 f->fp();

}

The code is compiled like this:

gcc winner.c -w -g -fno-stack-protector -z norelro -z execstack -o winner

(More code will be added later on so tags like fno-stack-protector are there)

I executed the project with argument "HELLO" and I set a break point on f->fp() and inspect the heap memory:

enter image description here

Everything after the first malloc() makes sense but I'm kinda puzzled about what happened after the second malloc(). The second chunk should only request 4 bytes of memory to store the function pointer but instead it took 12 bytes, which reflects on what is stored on the address 0x804a04c (4 bytes of metadata + 12 bytes of requested memory + status bit 1 = 17 => 0x00000011).

And as you can see, the function pointer did only take up four bytes on 0x804a050 with the address of nowinner (0x080484a1).

I read up on this SO post and this article but it seems it still can't explain why.

c
pointers
memory
asked on Stack Overflow Jan 24, 2018 by kevguy • edited Jan 24, 2018 by kevguy

1 Answer

3

Your initial question can be answered very easily by printing sizeof of your pointer. You will not see a 12 here.

The answer to your question "Why is function pointer 12 bytes long?" is simply: "It's not!"

But your question describes a different underlying question: "Why does allocating 4 bytes take 12 bytes on the heap?"

You are under the wrong impression that memory allocation only takes exactly what is needed to store the user data. This is wrong. Memory management also needs to store some management data for each allocation. When you call free the runtime library needs to know the size of the allocated block.

Therefore you can take it as granted that every allocation consumes more memory than the requested amount.

Depending on the implementation of the heap this can be within the heap itself or in a separate area. You can also not rely on taking the same amount of overhead for each allocation. There are weird implementation out there.

Some implementations take the requested amount and add fixed length of management data. Some implementations use a buddy system and follow a sequence of fibonacci numbers to determine smallest suitable block size.

answered on Stack Overflow Jan 24, 2018 by Gerhardh

User contributions licensed under CC BY-SA 3.0