tags:

views:

223

answers:

5

Can realloc fail in this case?

int *a = NULL;

a = calloc(100, sizeof(*a));
printf("1.ptr: %d\n", a);

a = realloc(a, 50 * sizeof(*a));
printf("2.ptr: %d\n", a);

if(a == NULL){
    printf("Is it possible?\n");
}

return (0);

}

The output in my case is:

1.ptr: 4072560
2.ptr: 4072560

So 'a' points to the same adress. So should I enforce realloc check?

Later edit:

  • Using MinGW compiler under Windows XP.
  • Is the behaviour similar with gcc on Linux ?

Later edit 2: Is it OK to check this way ?

int *a = NULL, *b = NULL;

a = calloc(100, sizeof(*a));
b = realloc(a, 50 * sizeof(*a));

if(b == NULL){
    return a;
}
a = b;
return a;
+7  A: 

Yes, you should always enforce a check on realloc, or any other memory allocation for that matter.

The current behavior of re-using the same address is an implementation detail that should not be relied upon. Doing so is just opening yourself up for bugs when either the library switches it's implementation or you move to a new platform.

Is it likely this will ever fail? Probably not, I'd be astounded if you could find a case that it does. However that doesn't mean it won't. Wrapping realloc in a function which automatically does the check for every operation is simple enough that there's no reason to not do it.

void* xrealloc(void* ptr, size_t size) {
  ptr = realloc(ptr, size);
  if ( !ptr ) {
    exit(EXIT_FAILURE);
  }
  return ptr;
}
JaredPar
Can you give an example when the reallocation of a memory patch that is smaller could fail?
hanno
@hanno, I can't and frankly I'd be surprised if it ever could. But using that as proof that it won't fail is making an argument from igonorance. I'd prefer to go the route of using a wrapper function which checks the return in all cases. It's simply safer to do so.
JaredPar
I also think is very unlikely to ever happen. Thanks for the xrealloc 'trick'. Can you please check to see if my check is valid.
Andrei Ciobanu
@nomemory your check is valid and looks OK to me assuming it's OK to return a with a larger size.
JaredPar
@JaredPar but if realloc fails, i want to hold a reference to a. Am I wrong ? I may misunderstood the whole free issue.
Andrei Ciobanu
@nomemory if realloc fails it should not alter the contents of the original pointer. So a will still point to the return value of calloc
JaredPar
@hanno: if your malloc implementation uses a bibop allocator and the smaller size needs to go on a new page as a result, but the page allocator fails to allocate a page, the realloc could fail. Of course, a smart allocator might choose to not free the old block and just return it, but its conceivable it could return NULL
Chris Dodd
+2  A: 

It is good practice to check the return value of realloc in any case (the specification doesn't say you are safer if you shrink your memory block than if you expand it). But you should be careful NOT to lose the initial pointer (which you do, in your case), as you'd then be completely unable to release it.

Romain
I've updated my example, with a check.
Andrei Ciobanu
+1  A: 

The C99 standard §7.20.3.4 (realloc) says:

The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.

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 the calloc, malloc, or realloc function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined. If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.

Returns

The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

Note that the old object is deallocated; the new object may happen to point to the same location as the old. And there could be problems. It is pretty unlikely, but it is far simpler to go with a rule 'always' than to have odd exceptions.

The normal counter-argument is "if this cannot fail, it means I have an error path that I cannot test". Up to a point, that is true. However, it could be that there has been some trampling of the memory so that the allocation cannot succeed - because the control information has been corrupted. More likely you'll just get a core dump, but maybe the code is robust enough to be able to avoid that. (I assume the hard coded 100 and 50 are for purposes of asking the question; real life code would not over-allocate when it knows how much it really needs.)

Where the two calls to 'realloc()' are adjacent, as here, there is very little room for anything to go wrong. However, real life working code would have some operations in between the two - and that code could cause the second 'realloc()' to fail.

Regarding your 'Edit 2'...

The code might be better written as:

if (b != NULL)
    a = b;
return a;

But the basic concept is OK. Note that the standard explicitly says that the original allocation is safe if the new one cannot be created.

Jonathan Leffler
Thanks for your answer. The code is 'dummy', just to understand the concept(s).
Andrei Ciobanu
Your code is nicer :)
Andrei Ciobanu
+4  A: 

It would be surprising if realloc failed when passed a size smaller than the original allocation, but nothing in the C standard (7.20.3.4) guarantees that it will always succeed:

The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.

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 the calloc, malloc, or realloc function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined. If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.

Returns

The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

A very simple conforming implementation of realloc would be this:

void *realloc(void *ptr, size_t size)
{
    void *new_ptr= malloc(size);
    if (new_ptr && ptr)
    {
        size_t original_size= _get_malloc_original_size(ptr);
        memcpy(new_ptr, ptr, min(original_size, size));
        free(ptr);
    }

    return new_ptr;
}

Under low memory conditions (or any conditions under which malloc would return NULL), this would return NULL.

It would also be a very simple optimization to return the same pointer if the size of the original allocation is greater than or equal to the requested size. But nothing in the C Standard dictates that.

MSN
Umm...where does it say a shrinking realloc will always succeed? I quote the same text and come to the inverse conclusion. I fear one of us is wrong.
Jonathan Leffler
@Jonathan Leffler: Umm...yes, where *does* it say that? I think you're both in the same boat here.
dreamlax
@Jonathan, I said "It would be surprising if realloc failed when passed a size smaller than the original allocation", not that shrinking realloc would always succeed. :) I suppose the wording is subtle enough to confuse.
MSN
+1  A: 

The time it takes to do the check is so small compared to the time spent in realloc() that I can't even see why it'd be a problem. Or do you want to reduce the number of lines of code?

Arthur Kalliokoski
I was just curious. :)
Andrei Ciobanu