What exactly is happening when I call free(a)?
This is implementation specific. As an example, with Linux and glibc, one of several things can happen:
If the memory was allocated in a block of 128k or more, glibc
will have allocated a new memory area (specifically, a copy-on-write mmap
of /dev/zero
). When it's freed, the memory area is simply deallocated (munmap
'd)and disappears. Further accesses will crash.
If the allocated memory was smaller, it will go on the heap. The heap is a single memory area starting at a fixed address, and is of a size that the process can shrink or increase (with sbrk
).
The memory allocator keeps tracks of which pieces of this area is allocated. The first time something is allocated, the size of heap is increased, and the memory is appended to the end in this new space.
If you free such a block of memory, at the end of the heap, the heap size can be reduced, thus making the memory invalid and making further accesses crash. The allocator will not increase or decrease the heap size for just a few bytes though, so at that point it depends on the size of the allocation and the number of blocks freed. It might be accessible, and it might not be.
If you allocate ten blocks of memory and free the first nine, you end up with an unused area in the heap. Since you can only modify the heap size by setting the end address, you can't really do anything about it. The memory is still valid, and accessing it will still work. You will probably even find your original data in it, and will be able to continue as if nothing happened.
However, as new memory is allocated, malloc
will try to put it in this unused area, thus letting other data overwrite what was originally there. Setting an int in your free'd array could then overwrite a pointer in a completely unrelated part of your program, and hilarity and debugging ensues.
tl;dr: Don't access free'd memory!