1

I have this code snippet to understand the memory management function void free(void*) in C. What I know about free function is that it will deallocate the memory that is managed by a pointer. I want to see what will happen after a block of memory is set free and whether the pointer associated is still accessible to that block of memory.

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

#define STR_SIZE 20

int main(int argc, char *argv[])
{
    char originalChar [] = "123456789";
    char *myChar = (char*) malloc(sizeof(char) * STR_SIZE);
    if (!myChar) {
        printf("allocation failed!");

        exit(1);
    }
    char *isOk = strncpy(myChar, originalChar, STR_SIZE*sizeof(char));
    if(!isOk) exit(1);

    char *myCharCopy = myChar;
    printf("oC = %d, mCC = %d; mC = %d\n", originalChar, myCharCopy, myChar);
    printf("The strings = %s\n", myChar);
    printf("The strings = %s\n", myCharCopy);
    free(myChar);
    printf("----- free happened here -----\n");
    // myChar = NULL;
    printf("oC = %d, mCC = %d; mC = %d\n", originalChar, myCharCopy, myChar);
    printf("The strings = %s\n", myChar);
    printf("The strings = %s\n", myCharCopy);

    return 0;
}

Then, I got those results from its output.

    oC = 1482066590, mCC = 826278544; mC = 826278544
    The strings = 123456789
    The strings = 123456789
    ----- free happened here -----
    oC = 1482066590, mCC = 826278544; mC = 826278544
    The strings = 123456789
    The strings = 123456789

This result makes very little sense to me. Because free function is supposed to set free the block of memory but it is NOT from the result. What on earth happened here? Besides, it seems the pointer associated with the memory on heap is still accessible to that freed memory. Why this will happen since it is freed?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Life
  • 449
  • 3
  • 9

2 Answers2

3

As per the C11 standard, chapter §7.22.3.3, The free function

The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation.[..]

It does not mandate that the pointer would be set to NULL (or anything else, for that matter). free()-ing is just an indication to the OS that the allocated memory can be reclaimed and reissued, as and when required.

Accessing free()-d memory is undefined behavior. So, once free() is called, you should not be accessing the pointer anymore.

For this very reason, it is often considered a good practice to set the free()-d pointer to NULL immediately after the call to free() so that to avoid any unintended access to already freed memory.


That said,

 printf("oC = %d, mCC = %d; mC = %d\n", originalChar, myCharCopy, myChar);

also invokes undefined behavior. %d is to print an int, not a pointer (or string, for that matter). In case you want to print the address, you may want to use

 printf("oC = %p, mCC = %p; mC = %p\n", (void*)originalChar, (void*)myCharCopy, (void*)myChar);
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • I saw people set `free()`-d pointer to `NULL`. Thank you. I was a little frustrated about those idioms though -- like to set it NULL after `free()`. Need to get used to it when learning it. – Life Jan 11 '16 at 20:18
  • I still met memory leaks even though I set `myChar` and `myCharCopy` to `NULL`. Why it happened? @Sourav Ghosh – Life Jan 11 '16 at 20:27
  • @Life memory leak? Where? BTW you did `free()` __and__ after that set it to NULL, right? – Sourav Ghosh Jan 11 '16 at 20:29
  • Yes. I did it like `free(myChar); myChar = NULL; myCharCopy = NULL;` – Life Jan 11 '16 at 20:30
  • @Life so where do you get a leak then? – Sourav Ghosh Jan 11 '16 at 20:31
  • From `valgrind --leak-check=yes ./myFile`, I saw the leak. @Sourav Ghosh – Life Jan 11 '16 at 20:32
  • I don't mean to bother you. But may I ask about those complaints from `valgrind`: `possibly lost: 2,064 bytes in 1 blocks ==14466== still reachable: 0 bytes in 0 blocks ==14466== suppressed: 24,238 bytes in 187 blocks` @Sourav Ghosh – Life Jan 11 '16 at 20:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/100412/discussion-between-life-and-sourav-ghosh). – Life Jan 11 '16 at 20:44
2

Per the C standard:

7.22.3.3 The free function

...

The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc , the behavior is undefined.

But now your code accesses the memory, which invokes undefined behavior, per the C Standard again:

J.2 Undefined behavior

1 The behavior is undefined in the following circumstances:

...

The value of a pointer that refers to space deallocated by a call to the free or realloc function is used (7.22.3).

Including appearing to "work".

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Ok. "Undefined behavior" is really hard to understand but I should get used to it. In addition, since `myChar` is freed, what will happen to `myCharCopy`, the one who points to the same piece of memory. Will it be a dangling pointer? – Life Jan 11 '16 at 20:13
  • 1
    @Life *what will happen to myCharCopy, the one who points to the same piece of memory. Will it be a dangling pointer?* It will indeed be a dangling pointer. Using memory after it's freed is a common bug. – Andrew Henle Jan 11 '16 at 20:16
  • Since this is a dangling pointer, do we need to set it to `NULL` too? Or we also need to `free()` it? @Andrew Henle – Life Jan 11 '16 at 20:20
  • 1
    @Life *Since this is a dangling pointer, do we need to set it to `NULL` too?* You don't *need* to - it's your code. It depends on what you want to do. If the variable is about to go out of scope because it's a local variable for a function that's returning, there'd be no need to set it to NULL. *Or we also need to `free()` it?* No, you shouldn't `free()` it. You can only use `free()` **once** on a pointer value you get from a call to `malloc()`, `calloc()`, etc. Doing otherwise is undefined behavior - that usually manifests itself as unexplained crashes later in execution. – Andrew Henle Jan 11 '16 at 20:53