35

What is the portable way to check whether malloc failed to allocate non-zero memory block?

Ziezi
  • 6,375
  • 3
  • 39
  • 49
pic11
  • 14,267
  • 21
  • 83
  • 119

5 Answers5

42

According to the Single Unix Specification, malloc will return NULL and set errno when it fails.

a3nm
  • 8,717
  • 6
  • 31
  • 39
  • 15
    `errno` **is thread-safe**. Do not listen to people who tell you otherwise. – R.. GitHub STOP HELPING ICE Jun 13 '11 at 01:59
  • 11
    The citation is XBD 3.396: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396 *A single flow of control within a process. Each thread has its own thread ID, scheduling priority and policy, errno value, thread-specific key/value bindings, and the required system resources to support a flow of control.* – R.. GitHub STOP HELPING ICE Jun 13 '11 at 02:03
  • 1
    `malloc()` returns `NULL` on failure. Even though OP exempted it with "to allocate non-zero memory block", `malloc(0)` can also return `NULL`. – chux - Reinstate Monica Dec 26 '18 at 22:51
  • 3
    The C standard makes no requirement that `errno` be set on a `malloc()` failure, so one can't rely on that in the general case. – Toby Speight Apr 11 '19 at 15:10
21

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."

Swift
  • 13,118
  • 5
  • 56
  • 80
  • 4
    You should also avoid writing `sizeof(char)`. Either use `sizeof *tok` or just nothing at all. – R.. GitHub STOP HELPING ICE Jun 13 '11 at 02:07
  • 1
    Wouldn't using sizeof(datatype) make it compatible across systems that use different sizes for that datatype? – Swift Jun 13 '11 at 02:08
  • 5
    Except this isn't an arbitrary datatype, it's `char`, and `sizeof` is in **units of char**. `sizeof(char)` is 1 by definition and conceptually it's something like a units error. Using `sizeof *dest_ptr` is a better practice anyway because it automatically adjusts if you ever change the type of `dest_ptr` (here `tok`) to something else. – R.. GitHub STOP HELPING ICE Jun 13 '11 at 02:11
  • Ah I think I understand now. So it's really on with `char` that sizeof is unnecessary overhead because it is always 1 across every system. Where if it were an `int` I would have to check because that varies? – Swift Jun 13 '11 at 02:15
  • 5
    Yes, with `int` you'd need to multiply by `sizeof(int)`. But again, it's the safest to directly get the size from the the size of the type being pointed to, i.e. `sizeof *tok` in your example. Then if you change the type and forget to update the `malloc` call, you won't be passing the wrong size. – R.. GitHub STOP HELPING ICE Jun 13 '11 at 02:31
  • 1
    As this is SO and we have to be pedantic, the OpenBSD folks suggest against multiplication to determine malloc size, as it can lead to integer overflow on poorly sanitized inputs. They define [reallocarray](http://lteo.net/blog/2014/10/28/reallocarray-in-openbsd-integer-overflow-detection-for-free/) to deal with this, but a more portable solution for this problem may be to use `calloc`. Of course there's a performance hit for zeroing the memory, but that's generally negligible. – bgw Apr 10 '15 at 18:50
  • There are situations where you may want or need to cast the result of `malloc`. For example, if you are compiling C code with a C++ compiler (such as for integrating your code with a larger C++ project), you should cast. In fact, you will be required to! – Alex Reynolds Dec 09 '16 at 20:52
9

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!

Community
  • 1
  • 1
David Leonard
  • 1,694
  • 1
  • 17
  • 14
7

Sure. The portable way is to test if malloc(...) returns NULL.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
4

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.

Fureeish
  • 12,533
  • 4
  • 32
  • 62
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256