56

Very simple question, I made the following program :

#include <stdlib.h>
int main(int argc, char ** argv)
{
    void * ptr;
    ptr = malloc(0);
    free(ptr);
}

And it does not segfault on my machine. Is it a portable behaviour of stdlib malloc and free, or am I looking for trouble ?

Edit : What seems non portable is the value returned by malloc. The question is about the malloc(0) + free combination, not the value of ptr.

shodanex
  • 14,975
  • 11
  • 57
  • 91
  • 2
    Bear in mind that, if this didn't work, there'd have to be a lot of special-case code. People will malloc a number of bytes based on a variable or expression all the time, and it would be awkward to have to check for zero each time. – David Thornley Oct 26 '09 at 13:33
  • related: http://stackoverflow.com/questions/2022335/whats-the-point-in-malloc0 – jldupont Jan 07 '10 at 18:23
  • I know: super late comment on this closed question. But there is _sometimes_ a use for `malloc(0)` that isn't mentioned. On those implementations where it returns a non-NULL value, especially in a DEBUG build, it likely allocates MORE than you asked for, and gives you the pointer to just past its internal header. This allows you to get a _feel_ for actual memory usage if you get this before and after a series of allocations. – Jesse Chisholm Feb 24 '17 at 17:57

7 Answers7

74

The behaviour is implementation defined, you will receive either a NULL pointer or an address. Calling free for the received pointer should however not cause a problem since:

  • free(NULL) is ok, no operation is done
  • free(address) is ok, if address was received from malloc (or others like calloc etc.)
Key
  • 6,986
  • 1
  • 23
  • 15
36

It's allowed to return NULL, and it's allowed to return a non-NULL pointer you can't dereference. Both ways are sanctioned by the standard (7.20.3):

If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.

dfa
  • 114,442
  • 31
  • 189
  • 228
  • 1
    This is not exactly the question asked. I don't care about the value returned by malloc, but about calling free on a pointer returned by malloc(0). – shodanex Jul 02 '09 at 09:32
  • 8
    It's still a very good answer because together with Key's answer it gives a complete overview over the behaviour. – schnaader Oct 26 '09 at 14:21
  • I think it is 7.22.3, not 7.20.3 - okay, so the answer was written in 2009, :) I meant 7.22.3 in C11 – aqjune May 08 '18 at 08:18
4

Sorry for the trouble, I should have read the man pages :

malloc() allocates size bytes and returns a pointer to the allocated memory. The memory is not cleared. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().

free() frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.

It seems it is true at least for the gnu libc

shodanex
  • 14,975
  • 11
  • 57
  • 91
3

According to the c standard

7.20.3 If the size of the space requested is zero, the behavior is implementation defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.

rohittt
  • 69
  • 1
  • 3
0

Though it might be legal C/C++, it is indicative a bigger problems. I generally call it 'pointer slopiness'.

See "Do not make assumptions about the result of malloc(0) or calloc(0)", https://www.securecoding.cert.org/confluence/display/seccode/VOID+MEMxx-A.+Do+not+make+assumptions+about+the+result+of+malloc%280%29+or+calloc%280%29.

Jeffrey Walton
  • 255
  • 2
  • 4
-1

Updated taking into account libt & Pax's comments:

The behaviour of calling malloc(0) is implementation dependant or in other words non-portable and undefined.

Link to CFaq question for more detail.

Aditya Sehgal
  • 2,867
  • 3
  • 27
  • 37
  • 4
    The ISO standards makes a very clear distinction between defined, implementation-defined and undefined. You should too. Implementation-defined means it *is* defined but the doco for that implementation will tell you what it does. Undefined means it can do *absolutely anything* including, but not limited to, total destruction of the universe. – paxdiablo Jul 02 '09 at 08:49
  • thanks for the clarification (and the down vote ;-) ). I used the term "undefined" rather loosely there. My bad. – Aditya Sehgal Jul 02 '09 at 16:14
  • You misunderstand the faq. it doesn't mean to say the overall behavior is implementation defined. It means that whether or not the result is NULL or some other value is implementation defined. For example, valid behavior does not include sending a sigsegv. – Johannes Schaub - litb Jul 02 '09 at 18:26
  • @aditya, the comment was mine, the downvote was not - I usually give people a chance to edit their answer before downvoting. – paxdiablo Jul 02 '09 at 22:58
  • @aditya, hold on. I didn't downvote you either :) – Johannes Schaub - litb Jul 03 '09 at 00:28
  • There ya go, have a +1 for changing it :-) – paxdiablo Jul 04 '09 at 01:15
  • great to see this answer changed, +1 – Johannes Schaub - litb Jul 04 '09 at 04:32
  • Having implementation-defined behaviour doesn't make the code non-portable. This code might have `ptr` null on one platform and non-null on another platform, but so long as it isn't dereferenced then the code is correct and will work the same. – M.M Aug 30 '15 at 05:37
-3

In my experience, I have seen that malloc (0) returns a pointer which can be freed. But, this causes SIGSEGV in later malloc() statements. And this was highly random.

When I added a check, for not to call malloc if size to be allocated is zero, I got rid of this.

So, I would suggest not to allocate memory for size 0.

-Ashutosh

  • ISO C requires zero-sized allocations to work. They may return either `NULL`, or a unique pointer that can be later passed to `free`. Your comment is not useful without a minimal repro test case, and naming the exact environment where that happened: compiler version, library, operating system. – Kaz Oct 25 '21 at 03:02
  • If a unique pointer is returned, it is subject to all the regular rules. You cannot access beyond its range and so that means that the pointer cannot be dereferenced: `((char *) ptr)]size]` is not a valid byte if `ptr` came from `malloc(size)`, and in this case `size` is 0. Moreover, you cannot free it two or more times. Once you free it, it becomes indeterminate; these pointers are susceptible to double free errors. A program which assumes that the result of `malloc(0)` can be freed two or more times will work on a platform where that returns NULL, but may fail elsewhere. – Kaz Oct 25 '21 at 03:08