You should think that realloc works like this:
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 can perform specific actions more efficiently than an implementation, but an implementation that works exactly as shown is 100% correct. This means that realloc(ptr, newsize) can fail at any time malloc(newsize) . in particular, it may fail even if you reduce the selection.
Now, on modern desktop systems, there is a strong example for not trying to recover from malloc crashes, but instead wrap malloc in a function (usually called xmalloc ) that immediately terminates the program if malloc fails; Naturally, the same argument applies to realloc . The point is this:
- Desktop systems often run in "overcommit" mode, where the kernel will happily transfer more address space than the RAM + swap operation can provide, assuming that the program will not actually use all of this. If a program tries to use all of this, it will be forced to terminate. On such systems, malloc will fail if you run out of address space, which is unlikely for 32-bit systems and almost impossible on 64-bit systems.
- Even if you are not in overcommit mode, the likelihood that the desktop system will have so much RAM and swap that long before you fail
malloc , the user will be fed up with his thrashed disk and forcibly terminate your program. - There is no practical way to test recovery from distribution failure; even if you had a gasket library that could precisely control which calls to
malloc failed (such gaskets are complicated at best, impossible to create depending on the OS), you will need to check the order 2 N where N is the number of calls in malloc in your program.
Arguments 1 and 2 do not apply to embedded or mobile systems (for now!), But argument 3 still remains there.
Argument 3 applies only to programs in which distribution errors must be checked and propagated at each call site. If you're so lucky to use C ++ as it is intended to be used (i.e. with exceptions), you can rely on the compiler to create error recovery paths for you, so the testing load is greatly reduced. And in any higher-level language that you should currently use, you have both exceptions and a garbage collector, which means you can't worry about distribution failures, even if you want.
zwol
source share