Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the chances that realloc should fail?

Does it fail when it runs out of free memory similar to malloc or could there be other reasons?

like image 658
user963241 Avatar asked Feb 07 '11 19:02

user963241


People also ask

What happens if realloc () fails?

If realloc() fails, the original block is left untouched; it is not freed or moved. On success, the reallocarray() function returns a pointer to the newly allocated memory. On failure, it returns NULL and the original block of memory is left untouched.

Does realloc always succeed?

( realloc will always succeed when you request to shrink a block.) If the input pointer is null, then realloc behaves exactly as if you had called malloc(size) , returning a pointer to the newly-allocated block of the requested size, or a null pointer if the request could not be satisfied.

Can realloc fail when shrinking?

realloc will not fails in shrinking the existing memory, so it will not return NULL .

What happens if you realloc 0?

Return Value If size is 0, the realloc() function returns NULL. If there is not enough storage to expand the block to the given size, the original block is unchanged and the realloc() function returns NULL. The storage to which the return value points is aligned for storage of any type of object.


3 Answers

Any of the allocation functions (malloc, realloc, calloc, and on POSIX, posix_memalign) could fail for any of the following reasons, and possibly others:

  • You've used up your entire virtual address space, or at least the usable portion of it. On a 32-bit machine, there are only 4GB worth of addresses, and possibly 1GB or so is reserved for use by the OS kernel. Even if your machine has 16GB of physical memory, a single process cannot use more than it has addresses for.
  • You haven't used up your virtual address space, but you've fragmented it so badly that no contiguous range of addresses of the requested size are available. This could happen (on a 32-bit machine) if you successfully allocate 6 512MB blocks, free every other one, then try to allocate a 1GB block. Of course there are plenty of other examples with smaller memory sizes.
  • Your machine has run out of physical memory, either due to your own program having used it all, or other programs running on the machine having used it all. Some systems (Linux in the default configuration) will overcommit, meaning malloc won't fail in this situation, but instead the OS will later kill one or more programs when it figures out there's not really enough physical memory to go around. But on robust systems (including Linux with overcommit disabled), malloc will fail if there's no physical memory left.

Note that strictly speaking, the allocation functions are allowed to fail at any time for any reason. Minimizing failure is a quality-of-implementation issue. It's also possible that realloc could fail, even when reducing the size of an object; this could happen on implementations that strictly segregate allocations by size. Of course, in this case you could simply continue to use the old (larger) object.

like image 57
R.. GitHub STOP HELPING ICE Avatar answered Oct 05 '22 05:10

R.. GitHub STOP HELPING ICE


You should think of realloc as working this way:

void *realloc(void *oldptr, size_t newsize)
{
   size_t oldsize = __extract_size_of_malloc_block(oldptr);
   void *newptr = malloc(newsize);

   if (!newptr)
     return 0;

   if (oldsize > newsize)
     oldsize = newsize;

   memcpy(newptr, oldptr, oldsize);
   free(oldptr);
   return newptr;
}

An implementation may be able to do specific cases more efficiently than that, but an implementation that works exactly as shown is 100% correct. That means realloc(ptr, newsize) can fail anytime malloc(newsize) would have failed; in particular it can fail even if you are shrinking the allocation.

Now, on modern desktop systems there is a strong case for not trying to recover from malloc failures, but instead wrapping malloc in a function (usually called xmalloc) that terminates the program immediately if malloc fails; naturally the same argument applies to realloc. The case is:

  1. Desktop systems often run in "overcommit" mode where the kernel will happily hand out more address space than can be backed by RAM+swap, assuming that the program isn't actually going to use all of it. If the program does try to use all of it, it will get forcibly terminated. On such systems, malloc will only fail if you exhaust the address space, which is unlikely on 32-bit systems and nigh-impossible on 64-bit systems.
  2. Even if you're not in overcommit mode, the odds are that a desktop system has so much RAM and swap available that, long before you cause malloc to fail, the user will get fed up with their thrashing disk and forcibly terminate your program.
  3. There is no practical way to test recovery from an allocation failure; even if you had a shim library that could control exactly which calls to malloc failed (such shims are at best difficult, at worst impossible, to create, depending on the OS) you would have to test order of 2N failure patterns, where N is the number of calls to malloc in your program.

Arguments 1 and 2 do not apply to embedded or mobile systems (yet!) but argument 3 is still valid there.

Argument 3 only applies to programs where allocation failures must be checked and propagated at every call site. If you are so lucky as to be using C++ as it is intended to be used (i.e. with exceptions) you can rely on the compiler to create the error recovery paths for you, so the testing burden is much reduced. And in any higher level language worth using nowadays you have both exceptions and a garbage collector, which means you couldn't worry about allocation failures even if you wanted to.

like image 34
zwol Avatar answered Oct 05 '22 07:10

zwol


I'd say it mostly implementation specific. Some implementations may be very likely to fail. Some may have other parts of the program fail before realloc will. Always be defensive and check if it does fail.

And remember to free the old pointer that you tried to realloc.

ptr=realloc(ptr,10);

is ALWAYS a possible memory leak.

Always do it rather like this:

void *tmp=ptr;
if(ptr=realloc(ptr,10)==NULL){
  free(tmp);
  //handle error...
}
like image 37
Earlz Avatar answered Oct 05 '22 05:10

Earlz