0

realloc may return either the same input address or a different address. If it returns a different address then it shall internally de-allocate/free the input memory and moving that content into an another location and returns that new address.

Please consider the following case.

new_ptr = realloc (2000, 10000)  // Lets assume the input address is 2000 

// Lets assume the new_ptr address is 3000

So, internally realloc shall free the memory where pointer points to 2000 and move those data into a new location 3000 and return the 3000 address.

Now the address 2000 is points to invalid. Hence it is not assigned to NULL by realloc API.

Now, passing that invalid address to realloc function. In real time there may be changes that realloc may get the invalid input address.

new_ptr = realloc(2000, 10000)

This 2000 address is invalid since it is already freed by previous realloc. Now the program crashes.

Can I resolve this issue by doing the following way.

      if (new_ptr != old_ptr ) {
        old_ptr = NULL;                      
      }

Since the old_ptr is invalid. I shall assign it to NULL. Please confirm me the correction.

  • You don't need to take any action. Just call `realloc`, that's all. – Jabberwocky Jul 20 '17 at 06:16
  • I... What? Why make everything so complicated? After realloc, use the new pointer, don't use the old pointer. Regardless of their values. – Art Jul 20 '17 at 06:16
  • (the only exception is when realloc returns NULL, then the old pointer hasn't been freed). – Art Jul 20 '17 at 06:16
  • 3
    I think it's an [XY problem](http://xyproblem.info/) as the OP doesn't seem to show us the real problem. – Andre Kampling Jul 20 '17 at 06:17
  • 1
    Always use the return value, it doesn't matter whether it's different. Use a temporary pointer to check for `NULL`, that's the only case you need the old pointer. –  Jul 20 '17 at 06:18
  • 1
    The problem is that after `realloc` succeeds *and* the area was freed, and a new one was allocated, *old pointer* will have indeterminate value, so you cannot compare `new_ptr != old_ptr`. – Antti Haapala -- Слава Україні Jul 20 '17 at 06:21
  • As Felix Palmen says use a temporary pointer: https://stackoverflow.com/a/21006798/8051589. – Andre Kampling Jul 20 '17 at 06:22
  • 4
    Calling `realloc()` with a pointer value that has already been freed leads to undefined behaviour. Any use of the 2000 pointer is now invalid. Anything may happen when you do use it. The program is not obliged to crash. It is not obliged not to crash. – Jonathan Leffler Jul 20 '17 at 06:47
  • @ Jonathan Leffler: You are right !!. – Arulprakasan Jul 20 '17 at 06:53
  • 2
    There's no portable way to know whether the block moved, and testing the old pointer is undefined behaviour – M.M Jul 20 '17 at 07:58

2 Answers2

5

Think about your first sentence:

realloc may return either the same input address or a different address.

This implies you can just use the return value as your new pointer, you don't have to know whether it's different from your previous one or not. If it is different, realloc() already handled freeing the previous block for you.

But there's one exception: realloc() may return 0 / NULL if the allocation fails. Only in this case, the old pointer is still valid. Therefore, the common idiom to use realloc() correctly looks like this:

T *x = malloc(x_size);
// check x for NULL

// [...]

T *tmp = realloc(x, new_size);
if (!tmp)
{
    free(x);
    // handle error, in many cases just exit(1) or similar
}
x = tmp; // use the new pointer, don't care whether it's the same

Note that using x (from my example above) after a successful call to realloc() is undefined, according to the C standard, x is invalid after the call. This doesn't tell you anything about the actual value of x. It just tells you "Don't use it, otherwise your program might do anything".

This self-quote might help you to understand what undefined behavior means:

Undefined behavior in C

C is a very low-level language and one consequence of that is the following:

Nothing will ever stop you from doing something completely wrong.

Many languages, especially those for some managed environment like Java or C# actually stop you when you do things that are not allowed, say, access an array element that does not exist. C doesn't. As long as your program is syntactically correct, the compiler won't complain. If you do something forbidden in your program, C just calls the behavior of your program undefined. This formally allows anything to happen when running the program. Often, the result will be a crash or just output of "garbage" values, as seen above. But if you're really unlucky, your program will seem to work just fine until it gets some slightly different input, and by that time, you will have a really hard time to spot where exactly your program is undefined. Therefore avoid undefined behavior by all means!.

On a side note, undefined behavior can also cause security holes. This has happened a lot in practice.

  • I accept Felix." If it is different, realloc() already handled freeing the previous block for you." . Now, Will the input_pointer is valid or invalid ?. realloc freeing the previous block is OK. But, Will it assign the old_ptr as NULL ? – Arulprakasan Jul 20 '17 at 08:50
  • What do you mean? If you want to accept this answer, [here's how](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work). You don't need to however, and if something is still unclear, feel free to ask. –  Jul 20 '17 at 08:53
  • @Arulprakasan regarding your edit: The pointer you were passing to `realloc()` isn't valid after the call if the return value was not `NULL`, and this is all you must know. Its value will not change (especially it is NOT set to `NULL`), it's just an invalid pointer you should forget as shown in the code snippet. –  Jul 20 '17 at 08:55
  • Why I am asking this question because for at some scenario the old_ptr may become a input for realloc. (old_ptr is now invalid) then what is the behavior ?? – Arulprakasan Jul 20 '17 at 08:59
  • No one understanding my exact question. My question is simple. How can i avoid passing the invalid input to the realloc function. That means, In the previous attempt realloc has deallocated/freed that input pointer also it is a dangling pointer. At same scenario the same pointer is passed as input to the realloc then what is the behavior ? how can we avoid it ? – Arulprakasan Jul 20 '17 at 09:12
  • No, you don't understand my answer, but I don't see how I could help you with this any further. Maybe take a step back and reread the answer as well as the helpful comments you received. –  Jul 20 '17 at 09:13
  • Please justify why this fix will not work? if (new_ptr != old_ptr ) { old_ptr = NULL; } After realloc I am making the old_ptr as valid by assigning that pointer to NULL. – Arulprakasan Jul 20 '17 at 09:20
0

Realloc will free the old memory block if it is successful. NOTE: if it can append in the same memory block it will append there itself. If it is not able to append it will create a new memory block and free the old one.

if you have any loop logic or you are using pointer that point to old memory block inside function after realloc is done.Than yes crash will come. if old pointer is just to do realloc than no need.Since local pointer you have created and its scope will be limited to that function.Every time you call the function it will be new pointer varaible.

Rohit
  • 142
  • 8
  • Thanks for understanding my question. How can we avoid passing the invalid pointer to the realloc function? Is this fix shall work ? If it is not, Any other solution is there ? if (new_ptr != old_ptr ) { old_ptr = NULL; } – Arulprakasan Jul 20 '17 at 11:10
  • 1
    @Arulprakasan, No! It is not the correct way. Previous answers and comments on the question have made it abundantly clear why. Please take a step back, read your question and all the comments once again. – Ajay Brahmakshatriya Jul 20 '17 at 12:38
  • if realloc is succesfull old_ptr should be re-init to NULL.So the later stage this invalid address should not be used by other statement. for ex:- void memory_allocater() { int *new_ptr = NULL; int *old_ptr= NULL; old_ptr = malloc(sizeof(int) * 10); if(NULL != old_ptr) { new_ptr = (int *)realloc (old_ptr, sizeof(int)*3); if (NULL != new_ptr ) { old_ptr = NULL; } } } – Rohit Jul 21 '17 at 03:52
  • @Rohit: Thanks for your answer. Seems this as well work fine. – Arulprakasan Jul 24 '17 at 05:25