How much memory does malloc(0) allocate?


Ad

Advertisements

E

Eric Sosman

How much memory does malloc(0) allocate?
http://prog21.dadgum.com/179.html

Interesting!

Not very. The author seems astonished that the Standard leaves
the matter up to the implementation, and calls it "a silly debate."
Okay, he's entitled to his opinion -- but "silly debate" isn't an
attempt to engage in meaningful discussion.

Sorry: I refuse to participate in Reddit.

http://www.nytimes.com/2013/07/28/m...spreading-of-a-smear.html?pagewanted=all&_r=0

The article, IMHO, is *much* too forgiving.
 
K

Keith Thompson

Lynn McGuire said:

C11 7.22.3p1:

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.

There's really not much more to say about it, and well-written code
shouldn't care whether malloc(0) returns a null pointer or not.
 
E

Eric Sosman

C11 7.22.3p1:

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.

There's really not much more to say about it, and well-written code
shouldn't care whether malloc(0) returns a null pointer or not.

In particular, an allocate-or-die function should look like

void *mallocOrDie(size_t bytes) {
void *new = malloc(bytes);
if (new == NULL && bytes > 0)
die("memory exhausted!");
return new;
}

The second part of the `if' condition is important, because the
first part alone is not proof of failure.
 
L

Lew Pitcher

http://www.reddit.com/r/programming/comments/1iv9nz/how_much_memory_does_malloc0_allocate/

C11 7.22.3p1:

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.

There's really not much more to say about it, and well-written code
shouldn't care whether malloc(0) returns a null pointer or not.

True, but well-written code should care if malloc(some_int_variable) returns
a null pointer or not.

Specifically, "f the space cannot be allocated, a null pointer is
returned".

Distinguishing this condition from "f the size of the space requested is
zero, ... a null pointer is returned ..." may be critical to the program
code.

For example, in implementations which return a null pointer from a call to
malloc(0), the following code

extern int memsize[];
extern char *memblock[];
extern int nmemsize;

#include <stdlib.h>

int counter;

for (counter = 0; counter < nmemsize; ++counter)
if ((memblock[counter] = malloc(memsize[memblock]) == NULL)
abort();

cannot distinguish between a problem with space allocation in malloc(), and
the (correct) allocation of a block of memory 0 bytes long.

Of course, the programmer could just code to evaluate the value that would
later be passed to malloc(), and select the appropriate processing based on
if it is zero or not.
 
Ad

Advertisements

M

Malcolm McLean

There's really not much more to say about it, and well-written code
shouldn't care whether malloc(0) returns a null pointer or not.
It'a very easy to write this

IMAGE *makeimage(int width, int height)
{
IMAGE *answer = maloc(sizeof(IMAGE));
if(answer) return 0;
answer->rgb = malloc(width * heoght * sizeof(PIXEL));
if(!answer->rgb)
{
free(answer);
return 0;
}
answer->width = width;
answer->height = height;
return answer;
}

But it means that code will behave differently on being asked to create the
empty image, which won't normally cause a problem, because people seldom use
the empty image. But eventually that's hard to track portability bug for
someone.
 
S

Siri Cruise

How much memory does malloc(0) allocate?

How much do you want it to allocate? You can always code

void *lynnmalloc(size_t n) {
return n==0 ? 0 : malloc(n);
}

or

void *lynnmalloc(size_t n) {
return n==0 ? malloc(1) : malloc(n);
}

And then you always have the answer you want.
 
J

James Kuyper

It'a very easy to write this

IMAGE *makeimage(int width, int height)
{
IMAGE *answer = maloc(sizeof(IMAGE));
if(answer) return 0;
answer->rgb = malloc(width * heoght * sizeof(PIXEL));
if(!answer->rgb)
{
free(answer);
return 0;
}
answer->width = width;
answer->height = height;
return answer;
}

But it means that code will behave differently on being asked to create the
empty image, which won't normally cause a problem, because people seldom use
the empty image. But eventually that's hard to track portability bug for
someone.

As he said: "well-written code". In this case, well-written implies that
it must work the same when height==0 || width==0, regardless of how the
implementation chooses to handle malloc(0). You have two main choices,
corresponding to the implementation's choices for malloc(0):

1. make it always act the way it would if malloc(0) were null - you must
check for height==0 || width==0, and if that is true, fail the same way
that you would if malloc(0) were null.

2. make it always act the way it would if malloc(0) were to behave the
same as malloc(n) for some non-zero value of n: check for height==0 ||
width == 0, and in that case call malloc(1), rather than malloc(0).

If you're doing this in two or more different places, it's simpler to
just write a wrapper for malloc() such that malloc_wrapper(n) handles
the case n==0 the way that you want it to be treated.
 
I

Ike Naar

It'a very easy to write this

IMAGE *makeimage(int width, int height)
{
IMAGE *answer = maloc(sizeof(IMAGE));

Assuming 'maloc' is a typo for 'malloc'.
if(answer) return 0;

Returns from the function if 'answer' is non-null.
Otherwise the statement below will be executed with 'answer' being null.
answer->rgb = malloc(width * heoght * sizeof(PIXEL));

Kaboom.
 
K

Kleuske

In particular, an allocate-or-die function should look like

void *mallocOrDie(size_t bytes) {
void *new = malloc(bytes); if (new == NULL && bytes > 0)
die("memory exhausted!");
return new;
}

The second part of the `if' condition is important, because the first
part alone is not proof of failure.

The wording in the standard above allows malloc(0) to return anything,
you just should not dereference the result.

The tricky part is where the standard allows a pointer to be returned,
but does not allow to dereference said pointer. It "shall" not be
dereferenced, but you can bet your hiney it will, sooner or later.
Murphy rules, after all. Thus the pointer returned is a timebomb, an
accident waiting to happen.

This leads me to conclude that attempting to allocate zero bytes isn't
good practice, *especially* when portability is an issue.

The "bytes > 0" check in the code above prevents ignominious crashes, but
masks a programming error. Memory isn't exhausted. Someone passed a bad
argument.

I would much prefer an solid assert instead.
 
Ad

Advertisements

L

Lynn McGuire

C11 7.22.3p1:

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.

There's really not much more to say about it, and well-written code
shouldn't care whether malloc(0) returns a null pointer or not.

The key here is "well-written" code. I daily
horse around with a 1.6 million line mix of
Fortran, C and C++. The Fortran code dates
back to the 1960s and believe you me, it is
not well written. Pointers (our Fortran uses
malloc extensively) are rarely checked for
validity.

Lynn
 
K

Keith Thompson

Keith Thompson said:
C11 7.22.3p1:

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.

There's really not much more to say about it, and well-written code
shouldn't care whether malloc(0) returns a null pointer or not.

That last sentence was probably a bit overstated and dismissive of some
real concerns.

I think that most code that calls malloc does so in such a way that it
*cannot* call malloc(0). Typically the argument is some positive
multiple of sizeof something, and sizeof always yields a positive
result.

But if malloc is used to allocate a dynamically sized buffer, it can be
possible for the size to be 0 -- and in that case, well-written code has
to take extra care to allow for the implementation-defined result of
malloc(0). "Well-written code" is code that takes this extra care so
that it doesn't have to care what malloc(0) returns.

And yes, this implementation-defined behavior is annoying. If the C
library were being designed from scratch today, I'm sure that the
behavior of malloc(0) would be defined one way or the other. It's the
way it is (presumably) because early pre-standard implementations did
not behave consistently, and the authors of the standard wanted to avoid
breaking code that depended on one particular behavior. (Such code was
already non-portable, but not all C code has to be portable.)
 
J

James Kuyper

... You have two main choices,
corresponding to the implementation's choices for malloc(0):

1. make it always act the way it would if malloc(0) were null ... ....
2. make it always act the way it would if malloc(0) were to behave the
same as malloc(n) for some non-zero value of n: ...

It occurs to me that there's a third option, not allowed by the standard
for malloc(), that is available for your wrapper. It relies upon a new
C2011 feature, max_align_t, to ensure that the pointer is correctly
aligned for conversion to any type. If the code cannot rely on C2011, a
more complicated approach is required.

malloc_wrapper.h:
#ifndef H_MALLOC_WRAPPER
#define H_MALLOC_WRAPPER
#include <stdlib.h>
extern void * const zero_alloc;
void *malloc_wrapper(size_t);
void free_wrapper(void *);
#endif

malloc_wrapper.c:
#include "malloc_wrapper.h"
#include <stddef.h>
static max_align_t dummy;
void * zero_alloc = &dummy;
void *malloc_wrapper(size_t size)
{
return size ? malloc(size) : zero_alloc;
}
void free_wrapper(void *ptr)
{
if(ptr != zero_alloc)
free(ptr);
}

In the unlikely event that your program makes large numbers of
zero-sized allocations, the memory not wasted by this wrapper could be
significant - but you need to be very careful to not call free(p), if
it's possible that p==zero_alloc.
 
R

Rosario1903

How much memory does malloc(0) allocate?
http://prog21.dadgum.com/179.html

i did not read these links...

for me malloc(0) can not return 0 because
that return 0 is the error condition

it has return some good memory;
for this or return some new memory
[a "header" of the that point to no memory... but it is memory...]
or use the same place i imagine something as

int memvoid[20];
void *b=(void*)memvoid;

void* malloc(u32 a)
{
if(a==0&& thereIsSomeMem()) return b;
....
}

void free(void* a)
{if(a==(void*)memvoid) return;
....
}

or something as that
 
E

Eric Sosman

The wording in the standard above allows malloc(0) to return anything,
you just should not dereference the result.

Not quite "anything." If it returns a non-NULL value, the value

- Must compare unequal to every other valid pointer value,
- Including NULL
- Including prior malloc(0) results not yet free()'d

- Must be convertible to any data pointer type and back again
to void* without damage

So, maybe s/anything/anything within reason/ ?
The tricky part is where the standard allows a pointer to be returned,
but does not allow to dereference said pointer. It "shall" not be
dereferenced, but you can bet your hiney it will, sooner or later.
Murphy rules, after all. Thus the pointer returned is a timebomb, an
accident waiting to happen.

This leads me to conclude that attempting to allocate zero bytes isn't
good practice, *especially* when portability is an issue.

The "bytes > 0" check in the code above prevents ignominious crashes, but
masks a programming error. Memory isn't exhausted. Someone passed a bad
argument.

The C99 Rationale (I haven't seen a C11 version yet) explains
the Committee's thinking; see section 7.20.3.
I would much prefer an solid assert instead.

Fine -- But in your usage, the assert should precede the
call to malloc(), and not depend on the returned value.
 
Ad

Advertisements

R

Rosario1903

for me malloc(0) can not return 0 because
that return 0 is the error condition

it has return some good memory;
for this or return some new memory
[a "header" of the that point to no memory... but it is memory...]
or use the same place i imagine something as

int memvoid[20];
void *b=(void*)memvoid;

void* malloc(u32 a)
{
if(a==0&& thereIsSomeMem()) return b;
...
}

void free(void* a)
{if(a==(void*)memvoid) return;
....
}

i forget realloc

void* realloc(void* p, size_t r)
{if(p==0||p==(void*)memvoid)
return malloc(r);
}
 
R

Rosario1903

malloc_wrapper.h:
#ifndef H_MALLOC_WRAPPER
#define H_MALLOC_WRAPPER
#include <stdlib.h>
extern void * const zero_alloc;
void *malloc_wrapper(size_t);
void free_wrapper(void *);
#endif

malloc_wrapper.c:
#include "malloc_wrapper.h"
#include <stddef.h>
static max_align_t dummy;
void * zero_alloc = &dummy;
void *malloc_wrapper(size_t size)
{
return size ? malloc(size) : zero_alloc;
}
void free_wrapper(void *ptr)
{
if(ptr != zero_alloc)
free(ptr);
}

In the unlikely event that your program makes large numbers of
zero-sized allocations, the memory not wasted by this wrapper could be
significant - but you need to be very careful to not call free(p), if
it's possible that p==zero_alloc.

there would be one "realloc wrapper" too
 
R

Rosario1903

Not quite "anything." If it returns a non-NULL value, the value

- Must compare unequal to every other valid pointer value,
- Including NULL
- Including prior malloc(0) results not yet free()'d

i don't understand why
"Must compare unequal...
Including prior malloc(0) results not yet free()'d"

if a=malloc(0) and v=malloc(0)
why a!=v
if both a and v point to 0 space mem
- Must be convertible to any data pointer type and back again
to void* without damage

so they have to point mem with address that can be the
address the restricter type
the machine can have... here would be double i think
 
Ad

Advertisements

E

Eric Sosman

It occurs to me that there's a third option, not allowed by the standard
for malloc(), that is available for your wrapper. It relies upon a new
C2011 feature, max_align_t, to ensure that the pointer is correctly
aligned for conversion to any type. If the code cannot rely on C2011, a
more complicated approach is required.

malloc_wrapper.h:
#ifndef H_MALLOC_WRAPPER
#define H_MALLOC_WRAPPER
#include <stdlib.h>
extern void * const zero_alloc;
void *malloc_wrapper(size_t);
void free_wrapper(void *);
#endif

malloc_wrapper.c:
#include "malloc_wrapper.h"
#include <stddef.h>
static max_align_t dummy;
void * zero_alloc = &dummy;
void *malloc_wrapper(size_t size)
{
return size ? malloc(size) : zero_alloc;
}
void free_wrapper(void *ptr)
{
if(ptr != zero_alloc)
free(ptr);
}

In the unlikely event that your program makes large numbers of
zero-sized allocations, the memory not wasted by this wrapper could be
significant - but you need to be very careful to not call free(p), if
it's possible that p==zero_alloc.

I think 7.22.3p1 forbids this dodge:

"If [malloc(0) returns non-null] the behavior is as if
the size were some nonzero value, [...]"

and (a few lines earlier)

"Each such allocation shall yield a pointer to an object
disjoint from any other object."

When the size is non-zero, a successful allocation must be
distinct from all other successful allocations (and from all
other valid pointers, null and non-null). That's part of the
behavior of a successful malloc(), and if malloc(0) undertakes
to imitate that behavior it must imitate the uniqueness, too.

Thus, in

void *p = malloc(0);
void *q = malloc(0);
assert (p == NULL || p != q);

.... I believe the assert must not fire.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top