-2

there is some confusion regarding my code below.

I allocate memory with malloc(), free it, then call realloc() with the same pointer ptr as the parameter, but don't use the return address from realloc.

This code compiles and runs fine printing the expected string. I didn't expect it to as ptr was previously freed.

If I however assign the return address from realloc() to ptr instead, which is commented out, there are of course runtime errors as expected , as ptr will be NULL.

Why does it work if I just pass the previously freed ptr as a parameter. It obviously allocates the memory again? Thanks in advance.

NOTE: This code was wrote intentionally just to try and understand what is happening in the background. De-referencing a dangling pointer etc. of course is not recommended.

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

int main()
{
    char* ptr;
    ptr = (char*)malloc(20);

    strcpy(ptr, "Hello");

    printf("Address before free : %d\n", ptr);
    printf("%s\n", ptr);

    free (ptr);

    printf("Address after free  : %d\n", ptr);
    printf("%s\n", ptr);

    realloc(ptr, 30);

    //ptr = realloc(ptr, 30); // causes runtime problem as expected

    strcpy(ptr, "Hello");

    printf("Address after realloc  : %d\n", ptr);
    printf("%s\n", ptr);

    return 0;
}
Engineer999
  • 3,683
  • 6
  • 33
  • 71
  • 6
    You dereference `ptr` after you call `free` using it, that leads to *undefined behavior*. You are also using the wrong format to print the pointer which is *also* leading to undefined behavior (you should be using `"%p"` to print `void*` pointers (and you really need to cast the pointer to `void*` to be valid)). This whole program is just a big exhibit on *undefined behavior*. Nothing it does can really be trusted to be correct. – Some programmer dude Dec 15 '16 at 15:09
  • Also think about it logically. If the `realloc` function needs to actually allocate new memory and copy the data to it, then it will return the pointer to the newly allocated memory. If you don't use it then `ptr` will still be pointing to the old memory. – Some programmer dude Dec 15 '16 at 15:11
  • 1
    If you call `realloc(ptr, 30);` after `ptr` has been freed, you get _undefined behavior_. – Jabberwocky Dec 15 '16 at 15:11
  • 1
    By the way, there is one *simple* change you can make to make the `realloc` call valid again: Make `ptr` be a null pointer. Then `realloc` will act like `malloc`. – Some programmer dude Dec 15 '16 at 15:12
  • Casting `malloc` and friends is useless in C. – alk Dec 15 '16 at 15:18
  • As @alk mentioned, [Please see this discussion on why not to cast the return value of `malloc()` and family in `C`.](http://stackoverflow.com/q/605845/2173917). – Sourav Ghosh Dec 15 '16 at 15:21
  • Thanks. Just a note. I wrote the code with an intention to make errors. This code for sure is not something i'd integrate anywhere. I am just trying to understand what is happening behind the scenes with bad code and the undefined behavior. – Engineer999 Dec 15 '16 at 15:26
  • Using the `printf` format specifier `%d` for pointers is really bad as the size of a pointer is often larger than the size of an `int`. – Andrew Henle Dec 15 '16 at 16:41

4 Answers4

7

For realloc(), specifically, quoting the C11 standard, chapter §7.22.3.5

If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size. Otherwise, if ptr does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined. [....]

That said, in this case, you've invoked undefined behavior well before that, by saying

printf("Address after free  : %d\n", ptr);
printf("%s\n", ptr);

where the mistakes are

  • %p is the required format specifier for a pointer, with the argumet casted to void *, not %d
  • attempt to use free()-d memory

which, both , individually and alone is sufficient to invoke UB.


Bottom line: Don't try to free() a pointer before passing it to realloc(), it will be taken care on it's own.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
2

The function called realloc() will reallocate the area of memory provided that it was previously allocated with malloc() calloc(), or realloc and not yet freed with making a call to free(). If free() is called on a piece of memory prior to realloc() will result in undefined behavior. Don't use realloc() with memory that has already been freed.

Best Regards!

Brandon83
  • 206
  • 1
  • 7
  • Thanks. I know realloc() shouldn't be used on freed memory. I was just testing it to see if it would result in a runtime error in this case – Engineer999 Dec 15 '16 at 15:33
  • 3
    @Engineer999, you cannot assume that a runtime error will occur when your program exhibits undefined behavior (as it does when it calls `realloc()` with an invalid pointer). You also cannot assume that absence of a runtime error means that your program is working correctly. – John Bollinger Dec 15 '16 at 15:41
0

Correct and demonstrative version of your program:

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

int main()
{
    char* ptr;
    ptr = malloc(20);

    strcpy(ptr, "Hello");

    printf("Address : %p\n", (void*)ptr);
    printf("%s\n", ptr);

    ptr = realloc(ptr, 30);   // expand the memory pointed by ptr
                              // from 20 to 30 bytes.

    printf("Address after realloc  : %p\n", (void*)ptr);  // address most likely different
    printf("%s\n", ptr);                           // displays still "Hello"
                                                   // as realloc preserves memory content

    free(ptr);     // eventually free what has been allocated previously
    return 0;
}

Sample output:

Address : 00767BC8
Hello
Address after realloc  : 00768C38
Hello

BTW: the addresses before and after realloc could potentially be the same, depending on the implementation.

Try to realloc less memory (e.g. 18), and the addresses will most likely be the same, but this is still implementation dependent.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • 2
    Better to store `realloc` retun value into a temp pointer to test if `realloc` fails. Otherwise the `ptr` memory leak. – LPs Dec 15 '16 at 15:46
  • 1
    `%d` is especially bad for pointers in a 64-bit environment as the size of the pointer at 8 bytes is most likely larger than an `int`, which is usually 4 bytes. – Andrew Henle Dec 15 '16 at 16:40
  • @alk done, I actually copy/pasted the wrong code into the answer. – Jabberwocky Dec 15 '16 at 16:41
0

ptr = realloc(ptr, 30);

This is bad. What if realloc fails, e.g. not enough memory and returns zero, then you loose your original pointer and you've got memory leak right there

dgrandm
  • 375
  • 3
  • 12