Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - Accessing data AFTER memory has been free()ed?

I'm reading a lot about malloc() and free() in Standard C. As I understand it, you malloc() for some memory exactly once and then you free() that same memory exactly once. It may be bad practice, but I understand that after you malloc() memory, you can define multiple pointers to it. And once you free() any of those pointers, the allocated memory is de-allocated?

Consider this toy example:

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

int main(){

    char* p = (char*)malloc(10 * sizeof(char));     // allocate memory
    int* q = (int*)p;                               // pointer to the same block of memory
    *p = 'A';                                       // Input some data
    printf("TEST::  %c %d\n", *p, *q);              // Everything's ok so far...
    free(p);                                        // free() my allocated memory?
    sleep(10);                                      // wait
    printf("%c\n", *q);                             // q now points to de-allocated memory
                                                    // shouldn't this segfault?

    free(q);                                        // *** SEGFAULTS HERE ***

    return 0;
}

Output is:

[Linux]$ ./a.out
TEST::  A 65

*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001ac4010 ***
======= Backtrace: =========
...lots of backtrack info...

So I assume that when I free() the first pointer, the memory is considered free()ed, but the data value(s) I wrote in this block of memory are still "there", which is why I can access them via the second pointer?

(I'm not proposing that this is a good idea, I'm trying to understand the logic of the system.)

like image 599
Pete Avatar asked Mar 03 '17 21:03

Pete


1 Answers

When you malloc memory, you're given a pointer to some space, and when you free it, you're giving it back to the system. Often, you can still access this memory, but using memory after you have freed it is VERY BAD.

The exact behavior is undefined, but on most systems you can either continue to access the memory, or you get a segfault.

One interesting experiment you can try is to try and malloc more memory after you free'd that pointer. On most systems I've tried, you get the same block back (which is a problem, if you were relying on the data being there in the freed block). Your program would end up using both pointers, but since they point to the same physical data, you'll be overwriting your own data!

The reason for this is that when you malloc data (depending on the malloc implementation of course), malloc first requests a block of data from the operating system (typically much larger than the malloc request), and malloc will give you a segment of that memory. You'll be able to access any part of the memory malloc originally got from the operating system though, since to the operating system, it's all memory your program is internally using. When you make a free, you're telling the malloc system that the memory is free, and can be given back to the program later on.

Writing outside of the malloc area is very dangerous because

  1. It can segfault, depending on your c implementation
  2. You can overwrite metadata structures malloc is relying on, which causes VERY BAD PROBLEMS when you free/malloc more data later on

If you are interested in learning more, I would recommend running your program through valgrind, a leak detector, to get a better picture of what's freed/not freed.

PS: On systems without an OS, you most likely wont get a segfault at all, and you'll be able to wite anywhere willy nilly. The OS is responsible for triggering a segfault (when you write/read to memory you don't have access to, like kernel or protected memory)

If you are interested in learning more, you should try to write your own malloc, and/or read/learn about the memory management operating systems do.

like image 189
Jay Kamat Avatar answered Sep 18 '22 10:09

Jay Kamat