How detect malloc failure?
What is the portable way to ch开发者_JAVA百科eck whether malloc
failed to allocate non-zero memory block?
According to the Single Unix Specification, malloc
will return NULL
and set errno
when it fails.
I always do this:
tok = malloc( sizeof( char ) * ( strlen(tc) + 1 ) );
if( tok == NULL )
{
/* Malloc failed, deal with it */
}
Some people do tok = (type) malloc( ... )
but you should cast the result because apparently it covers up some nasty errors. I will do some research and see if I can find out exactly what they are.
Edit:
Casting malloc can hide a missing #include <stdlib.h>
I found this link which contained a very good explanation:
http://cboard.cprogramming.com/faq-board/25799-faq-casting-malloc.html
"So when you say this (char*)malloc(10)
You're saying that you take whatever malloc returns, convert it to a char*, and assign that to the variable in question.
This is all well and good if malloc is prototyped properly (by including stdlib.h), where it's defined as returning void*.
The problem comes in when you fail to include stdlib.h, and the compiler initially assumes that malloc returns an int. The real problem is, you DONT get any warning from the compiler.
You merrily then convert that int to a char* (via the cast). On machines where sizeof(char*) is different from sizeof(int), the code is seriously broken.
Now if you just have char *var = malloc( 10 ); And you miss out the include , you will get a warning from the compiler."
You can detect failure when:
malloc(n)
returns NULL
This is the most common and reliable test to detect an allocation failure. If you want to be portable beyond POSIX/SUS, I wouldn't trust errno
though. If you need detail, say for logging, I'd zero errno
before the call, see if it changed, then maybe log that.
malloc(n)
returns a non-NULL
address which is not backed by actual memory
Touch it and see if you get killed by the OS. Yes, this can happen. It's called memory overcommit and resembles fractional reserve banking. It's the optimistic approach of an OS or hypervisor to return addresses to virtual memory they're gambling they won't ever have to actually provide. This happens on Linux, VMware. (I can't find any explicit evidence of Windows overcommitting, although requested pages are only "committed" when they are touched.)
The question then is "how do I portably detect if my program is about to crash on accessing an address I got from the malloc I previously trusted like a teenage crush?". One way might be to read()
a random file into the test area and see if the OS returns EINVAL or equivalent.
For extra points,
malloc(0)
returns NULL
and leaves errno
undefined
I know the question asked for "non-zero [sized] memory block", but this is interesting. Consider a SUS-compliant allocator that intends to return non-NULL
for a zero-sized allocation (it can do that), but then it fails, so it has to return NULL
. And it could try to set errno
. Is that a failure? I think Hoare says we paid a billion dollars for this ambiguity. So, calling malloc(0)
is not portable and the questioner probably knew that!
Sure. The portable way is to test if malloc(...)
returns NULL
.
malloc(n)
returns NULL
on failure.
malloc(0)
may return NULL
.
To detect failure:
void* ptr = malloc(n);
if (ptr == NULL && n > 0) Handle_Failure();
Notes:
As in OP's case: "... allocate non-zero memory block", often code is such that a 0
allocation request can not occur and so the 0
test is not needed.
size_t nstr = strlen(some_string) + 1;
void* ptrstr = malloc(nstr);
if (ptrstr == NULL) Handle_Failure();
Some systems set errno
on failure, but not all. Setting errno
due to memory allocation failure is not specified in the C11 spec.
malloc(n)
expects n
to be the unsigned type size_t
. Using an int n
with a negative value will certainly convert to some large unsigned value and then likely fail the memory allocation.
精彩评论