8

I am learning and testing memory allocation in C and I want to test what happens if free() is called.

I expected there could be a segmentation fault or pointer is NULL after I run the program below. However, I can still successfully print the string as in Output. I also tried to free str twice, then an error as Output 2 occurred.

It seems the previously allocated memory is successfully deallocated, but the data on the memory is not cleaned up. Is that correct? If that is the case, when will the program clean up those deallocated memory space? Is that safe if the data is deallocated but not cleaned up?

Answers to any question above will be helpful! Thanks!

Code

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

int main()
{
    printf("Hello, World!\n");
    char *str = (char *)malloc(24);
    char *str2 = "tutorialspoint";
    strcpy(str, str2);
    free(str);
    printf("[str] %s\n", str);
    return 0;
}

Output

Hello, World!
[str] tutorialspoint

Output 2

main(83218,0x7fff9d2aa3c0) malloc: *** error for object 0x7fb0b2d00000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

Edit

Thank you all for helpful replies. Now I understand that there are some undefined behaviors (UB) in C and this helped me understand something else confused me before such as writing to a string beyond the scope of allocated(like what's in the code snippet below). This caused UB according to wiki, but the program will not crash.

Feel free to correct me if I got it wrong!

char *str = (char *)malloc(0);
char *str2 = "tutorialspoint";
strcat(str, str2);
printf("[str] %s, [addr] %p\n", str, str);
Peter Paul
  • 384
  • 3
  • 13
  • 3
    Probably many duplicate questions. Having released the memory with `free` it is available for other use. If it still works, you were unlucky that a fault didn't alert you to the coding error. – Weather Vane Jul 19 '17 at 18:50
  • @Peter Paul, What did you expect to happen? – chux - Reinstate Monica Jul 19 '17 at 18:51
  • @WeatherVane Unlucky instead of lucky, that's the correct word. – Iharob Al Asimi Jul 19 '17 at 18:53
  • @IharobAlAsimi I already wrote "unlucky". The comment edit was a different typo. Consider the phrasing. – Weather Vane Jul 19 '17 at 18:54
  • @WeatherVane I know. I meant, that sometimes the word *lucky* is used where *unlucky* makes more sense. – Iharob Al Asimi Jul 19 '17 at 18:59
  • @IharobAlAsimi I get you now, you reinforced my comment. – Weather Vane Jul 19 '17 at 19:00
  • @yano presumably the lesson from the well-received answer you linked, is to `free(p); p = NULL;` – Weather Vane Jul 19 '17 at 19:08
  • @chux and Weather Vane I am expecting a 'memory already deallocated error' here because I tried to print the variable after I freed them. It seems to be a UB as mentioned by many people on this post. Then my next question is: Is that safe if the memory space isn't clean up after deallocation? Will the memory be cleaned up before the next time the same memory space is allocated again? – Peter Paul Jul 19 '17 at 19:14
  • @yano "you hope not" - what do you have against setting a pointer to `NULL`, when its previous **value** (not what it points to) can supposedly not even be read? – Weather Vane Jul 19 '17 at 19:31
  • @PeterPaul That is the thing about UB. You may get "memory already deallocated error" on one run of code, on another you may a `seg-fault`, on another nothing bad happens, on another your disk is wiped clean. It is undefined. "Is that safe if the memory space isn't clean up after deallocation?" --> For the most part, yes, the memory will be free'd when code closes, but may consume resources in the meantime, "Will the memory be cleaned up before the next time the same memory space is allocated again?" Do not expect this, until the program closes. – chux - Reinstate Monica Jul 19 '17 at 19:33
  • @WeatherVane Nothing, my apologies, spaced out for a second there,, misinterpreted what you said. – yano Jul 19 '17 at 19:35
  • To be clear:after freeing `ptr`, not only is `*ptr` UB, even copying the old pointer value `void *p = ptr;` is UB. – chux - Reinstate Monica Jul 19 '17 at 19:36
  • @PeterPaul no, after you `free` the memory it is no concern of yours at all. The memory manager won't remember the history of what you did with the pointer, even less the C code that used it. So don't expect any kind of report. The memory is yours to use, and if it isn't anything might happen - even apparent success. – Weather Vane Jul 19 '17 at 19:36
  • @WeatherVane "The memory manager won't remember the history of what you did with the pointer, even less the C code that uses it" again is one of those ideas that is not supported by C, nor the OS. It is UB. After freeing memory the "memory manager" may very well keep track of all sorts of things. Assuming anything about free'd memory provides for a hacker exploit like searching free'd memory for tell-tale passwords, etc. – chux - Reinstate Monica Jul 19 '17 at 19:40
  • @chux sorry, my comment does not support your theory. Please read more carefully. – Weather Vane Jul 19 '17 at 19:42
  • 1
    @chux Thanks for your explanation! It's very helpful! I was just testing the behaviors of `free()`. I think now I can understand some strange behaviors I met before with memory allocation. – Peter Paul Jul 19 '17 at 19:46

2 Answers2

11

You need to learn the concept of undefined behavior.

Even if you print the string after you free it and it "works", it doesn't mean it worked. It's just one of the things that can happen when the behavior is said to be undefined, which in this case it is.

Also, the pointer will not be NULL except if you do this

free(ptr);
ptr = NULL;

and free(), doesn't set all bytes to 0 either.

The free() function just does exactly what it's name suggests. It allows malloc() to use the free()d chunk again. The data the pointer pointed to might still be there unchanged and that is the reason why you can still print the previous content after free(). But there is absolutely no guarantee of what will happen if you do dereference a pointer after free() or whether the data still exists or, was completely or partially overwritten.

If you do dereference the pointer after having free()d it, there is one thing you do know, the behavior is undefined.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • @PeterPaul, probable. You can't rely on what is there immediately after `malloc()`. You need to explicitly initialize the returned memory with some data. – Iharob Al Asimi Jul 19 '17 at 19:37
6

When you call free, it allows the pointed-to memory to be used for other purposes. Attempting to read or write memory that has been freed invokes undefined behavior.

Just because the memory has been given up doesn't necessarily mean it's been physically wiped.

An analogy: Suppose you left a book on your hotel room table. You check out of the hotel, but you still have the key card. If you go back to the room the book might be there, or it might not.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • @PeterPaul find the long version of the UB analogy [here](https://stackoverflow.com/a/6445794/3476780). This links to a `c++` answer and a different type of UB, but UB nonetheless and it applies to `c` as well – yano Jul 19 '17 at 19:03