Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does malloc(1) work for storing 4 byte integers?

Tags:

c

memory

malloc

From what I understand, malloc(x) returns a block of memory x bytes long.

So to store a 4 byte integer, I would do:

int *p = (int *)malloc(4);
*p = 100;

Because sizeof(int) returns 4 for me.

However, if I do:

int *p = (int *)malloc(1);
*p = 100;

It seems to work exactly the same, with no issues storing the value.

Why does the amount of memory requested with malloc() not seem to matter? Shouldn't a 4 byte integer require malloc(4)?

like image 904
cprogrammer Avatar asked Dec 07 '22 19:12

cprogrammer


2 Answers

If this works in your case it just works by chance and is not guaranteed to work. It is undefined behavior (compare this SO question) and everything can happen.

What did you expect to happen? Your program crash?

That might still happen if you call malloc and free a bit more often. malloc often takes some bytes more than requested and uses the extra space for Managing (linked list of all memory blocks, sizes of memory blocks). If you write some bytes before or after your allocated block then chances are high that you mess with the internal management structures and that subsequent malloc of free will crash.

If malloc internally always allocates a minimum of n bytes then your program might only crash if you access byte n+1. Also the operating system normally only be protects memory based on pages. If a page has a size of 512 bytes and your malloc-ed byte is in the middle of a page then your process might be able to read-write the rest of the page and will only crash when accessing the next memory page. But remember: even if this works it is undefined behavior.

like image 163
Werner Henze Avatar answered Dec 11 '22 10:12

Werner Henze


malloc as all memory block allocation functions from C runtime or OS Kernel are optimized for memory access and object alignment.

Moreover, malloc specifically, allocate an hidden control block in front of the allocated space to keep track of the allocation (space required, space allocated, etc).

malloc must also to guarantee that the allocated memory address is suitably aligned for any storage object, this means that the block will start on an 8, 16, 32 or even 64 or 128 bytes boundary depending on the processor and generically from hardware (i.e. some special MMU). The boundary is also dependent on access speed, some processor have different behavior with different memory accesses (1, 2, 4, 8, ... bytes) and address boundaries. This constraints drive malloc code spec and allocator logical memory blocks partitions.

On practical side lets consider an allocator for X86 processor, it generally give back a block aligned on an 8 bytes boundary (32 bits code), that is useful for int, float and even doubles. To do this malloc divides the available memory arena in 'blocks' that are the minimal allocation space. When you allocate even 1 byte the function allocates at least one block. Eventually this block can host an integer, or even a double, but it is implementation dependent, and you can't consider it deterministic, because in future versions of the same function the behavior can change.

Now that, I hope, is clear because your code seems to work, keep well in mind that this is Undefined-Behavior and you must keep it for that. IT can work now, not with the next revision, it can crash on some hardware and not on another processor or machine.

like image 23
Frankie_C Avatar answered Dec 11 '22 09:12

Frankie_C