what malloc(0) should returns?

C

CBFalconer

Random832 said:
.... snip ...

I think typically systems (at least, UNIX systems) that don't return
NULL return the same printer every time. It's not really clear why
they'd have to be different.

p1 = malloc(0); p2 = malloc(0); p2 = realloc(p2, 100);

(Ignore the misuse of realloc). Now, if p2 had free space above
it, p2 might be unchanged. However p1 is still pointing to zero
bytes. You would get very funny results by depending on "if (p1 ==
p2)".
 
K

Keith Thompson

Bill Medland said:
Well, I expect it frequently does allocate memory; it presumably just
allocates enough for its own management purposes rather than what it needs
and what the caller wants (and the text is the usual user-intended
Microsoft text rather than the pedantic version)

Or it allocates a unique (and invalid) address without allocating any
memory at that address. free() might then require an extra test to
detect the implementation-defined pointers returned by malloc(0).
 
J

Jack Klein

A quick test of a few systems I happen to have immediate access to
shows that all of them either return a null pointer, or return
distinct values on two successive calls to malloc(0).

As for why this is required, C99 7.20.3p1 says:

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.

One aspect of the behavior of malloc() with a non-zero size is that
successive calls return unique values. My interpretation is that this
same behavior is required for non-null results of malloc(0).

Do you have a standard citation for that?

Is there any reason why, in a suitable function with a suitable
implementation and suitable includes:

uintptr_t pu, qu;
void *p = malloc(100);
pu = (uintptr_t)p;
free (p);
p = malloc(100);
qu = (uintptr_t)p;
if (pu == qu)
do_something();
else
do_something_else();

....are you claiming that pu and qu must compare unequal because they
were returned by successive calls to malloc()?

Any program that depends on malloc() never returning the same pointer
twice, especially with intervening calls to free(), is broken.
 
K

Keith Thompson

Jack Klein said:
Do you have a standard citation for that?

Um, C99 7.20.3p1?
Is there any reason why, in a suitable function with a suitable
implementation and suitable includes:

uintptr_t pu, qu;
void *p = malloc(100);
pu = (uintptr_t)p;
free (p);
p = malloc(100);
qu = (uintptr_t)p;
if (pu == qu)
do_something();
else
do_something_else();

...are you claiming that pu and qu must compare unequal because they
were returned by successive calls to malloc()?

Yes, I am.
Any program that depends on malloc() never returning the same pointer
twice, especially with intervening calls to free(), is broken.

Multiple calls to malloc() with non-zero arguments, assuming they all
succeed, must return distinct pointers, assuming there are no
intervening calls to free().

If malloc(0) returns a non-null result, then it must behave as if it
were called with a non-zero argument; it seems to me that means
returning distinct values.

On the other hand, a portable application can't depend on malloc(0)
returning a non-null result anyway, so the guarantee doesn't do much
good.
 
J

jaysome

David T. Ashley said:


It's stricter than that. It's not just implementation-dependent, but
implementation-defined. That means that the implementation's documentation
must tell you which choice it made.

For example, Microsoft's C compiler documentation says:

+++
C Language Reference
Allocating Zero Memory

ANSI 4.10.3 The behavior of the calloc, malloc, or realloc function if the
size requested is zero

The calloc, malloc, and realloc functions accept zero as an argument. No
actual memory is allocated, but a valid pointer is returned and the memory
block can be modified later by realloc.
+++

In the same compiler documentation, further clarification is given:

<quote>
malloc

void *malloc( size_t size );
....
If size is 0, malloc allocates a zero-length item in the heap and
returns a valid pointer to that item. Always check the return from
malloc, even if the amount of memory requested is small.
</quote>

This compiler documentation uses a non-standard,
implementation-specific term such as "heap" to further "clarify"
things (The concept of a "heap" is second hand news to any serious
developer for the WIN32 platform).

The last sentence in the above quote is meant for your own good, and
has nothing to do with how the OS might misbehave (though it could).
All WIN32 platforms--95/98/ME/NT/2K/XP/2003/Vista/32/64--gracefully
handle null pointer dereferences.

Thanks Microsoft
 
C

Chris Dollin

CBFalconer said:
p1 = malloc(0); p2 = malloc(0); p2 = realloc(p2, 100);

(Ignore the misuse of realloc). Now, if p2 had free space above
it, p2 might be unchanged. However p1 is still pointing to zero
bytes. You would get very funny results by depending on "if (p1 ==
p2)".

If an implementation chose to return
the same pointer P for each malloc(0)
then realloc would need to know
that P was operationally equal
to null, and hence in your code above
the realloc would just mallocate
100 bytes for your convenience.

Wouldn't it?
 
R

Richard Bos

Chris Dollin said:
If an implementation chose to return the same pointer P for each malloc(0)
then realloc would need to know that P was operationally equal
to null, and hence in your code above the realloc would just mallocate
100 bytes for your convenience.

Ok, now try this one:

char *p1, *p2;
p1=malloc(0); p2=malloc(0);
p1=realloc(p1, 200);
p2=realloc(p2, 100);
p1[123]='?';

If subsequent (non-free()d) calls to malloc(0) were allowed to deliver
identical pointers, that code would be allowed to make flying reindeer
come out of the North Pole. But Santa is just a cheap copy of the real,
Dutch, Saint Nicholas, and that code (bad use of realloc() excepted)
does not have undefined behaviour. Therefore, all pointers returned from
malloc(0) must be either null or not equal to any other pointer,
including ones obtained from other calls to malloc(0).

Richard
 
C

Chris Dollin

Richard said:
Chris Dollin said:
If an implementation chose to return the same pointer P for each malloc(0)
then realloc would need to know that P was operationally equal
to null, and hence in your code above the realloc would just mallocate
100 bytes for your convenience.

Ok, now try this one:

char *p1, *p2;
p1=malloc(0); p2=malloc(0);
p1=realloc(p1, 200);
p2=realloc(p2, 100);
p1[123]='?';

If subsequent (non-free()d) calls to malloc(0) were allowed to deliver
identical pointers, that code would be allowed to make flying reindeer
come out of the North Pole. But Santa is just a cheap copy of the real,
Dutch, Saint Nicholas, and that code (bad use of realloc() excepted)
does not have undefined behaviour. Therefore, all pointers returned from
malloc(0) must be either null or not equal to any other pointer,
including ones obtained from other calls to malloc(0).

I don't know if it's your metaphor or the imminent arrival of the
holiday or what, but I can't see why your example poses a problem
to the tactic in my remark above. Could you unpack?
 
C

CBFalconer

Chris said:
If an implementation chose to return the same pointer P for each
malloc(0) then realloc would need to know that P was operationally
equal to null, and hence in your code above the realloc would just
mallocate 100 bytes for your convenience.

No reason for that complication. It isn't required by the
standard. The following (from N869) is adequate:

7.20.3 Memory management functions

[#1] The order and contiguity of storage allocated by
successive calls to the calloc, malloc, and realloc
functions is unspecified. The pointer returned if the
allocation succeeds is suitably aligned so that it may be
assigned to a pointer to any type of object and then used to
access such an object or an array of such objects in the
space allocated (until the space is explicitly freed or
reallocated). Each such allocation shall yield a pointer to
an object disjoint from any other object. The pointer
returned points to the start (lowest byte address) of the
allocated space. If the space cannot be allocated, a null
pointer is returned. 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. The value of a pointer
that refers to freed space is indeterminate.

Note that a freed pointer DOES NOT point to an object.
 
C

Chris Dollin

CBFalconer said:
Chris said:
If an implementation chose to return the same pointer P for each
malloc(0) then realloc would need to know that P was operationally
equal to null, and hence in your code above the realloc would just
mallocate 100 bytes for your convenience.

No reason for that complication. It isn't required by the
standard. The following (from N869) is adequate:

7.20.3 Memory management functions

[#1] The order and contiguity of storage allocated by
successive calls to the calloc, malloc, and realloc
functions is unspecified. The pointer returned if the
allocation succeeds is suitably aligned so that it may be
assigned to a pointer to any type of object and then used to
access such an object or an array of such objects in the
space allocated (until the space is explicitly freed or
reallocated). Each such allocation shall yield a pointer to
an object disjoint from any other object. The pointer
returned points to the start (lowest byte address) of the
allocated space. If the space cannot be allocated, a null
pointer is returned. 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. The value of a pointer
that refers to freed space is indeterminate.

Note that a freed pointer DOES NOT point to an object.

You're arguing that the standard says that multiple malloc(0)s
shall not re-use the same pointer value, yes? That's fine
then.

If it /didn't/ explicitly forbid it, then I don't see that
there would be a problem. Other posters (eg Random832) seemed
to be arguing that there would.

I am not arguing that the choice "malloc(0) always returns the
same pointer" would be /sensible/ if it were legal, just that
it could be made to work consistently.
 
C

CBFalconer

Chris said:
Chris said:
CBFalconer wrote:
Random832 wrote:

... snip ...

I think typically systems (at least, UNIX systems) that don't return
NULL return the same printer every time. It's not really clear why
they'd have to be different.

p1 = malloc(0); p2 = malloc(0); p2 = realloc(p2, 100);

(Ignore the misuse of realloc). Now, if p2 had free space above
it, p2 might be unchanged. However p1 is still pointing to zero
bytes. You would get very funny results by depending on "if
(p1 == p2)".

If an implementation chose to return the same pointer P for each
malloc(0) then realloc would need to know that P was operationally
equal to null, and hence in your code above the realloc would just
mallocate 100 bytes for your convenience.

No reason for that complication. It isn't required by the
standard. The following (from N869) is adequate:

7.20.3 Memory management functions

[#1] The order and contiguity of storage allocated by
successive calls to the calloc, malloc, and realloc
functions is unspecified. The pointer returned if the
allocation succeeds is suitably aligned so that it may be
assigned to a pointer to any type of object and then used to
access such an object or an array of such objects in the
space allocated (until the space is explicitly freed or
reallocated). Each such allocation shall yield a pointer to
an object disjoint from any other object. The pointer
returned points to the start (lowest byte address) of the
allocated space. If the space cannot be allocated, a null
pointer is returned. 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. The value of a pointer
that refers to freed space is indeterminate.

Note that a freed pointer DOES NOT point to an object.

You're arguing that the standard says that multiple malloc(0)s
shall not re-use the same pointer value, yes? That's fine
then.

If it /didn't/ explicitly forbid it, then I don't see that
there would be a problem. Other posters (eg Random832) seemed
to be arguing that there would.

I am not arguing that the choice "malloc(0) always returns the
same pointer" would be /sensible/ if it were legal, just that
it could be made to work consistently.

No it couldn't. Think about pointer comparisons. Then think about
what other anomalies could exist. But one is enough to show it is
a bad idea.
 
T

trm

^^^^^^^^
Yes, I am.

Er, I suspect this would break a lot of code...
Multiple calls to malloc() with non-zero arguments, assuming
they all succeed, must return distinct pointers, assuming
there are no intervening calls to free().

....I believe you may have misspelled "No, I'm not" up above.
Would you mind clarifying your clarification?
 
S

Stephen Sprunk

Keith Thompson said:
So the memory allocated for the header isn't "actual memory"?

It depends on your perspective. Since malloc() returns an address
*after* the header, user code cannot legally access the header since
it's not part of the object returned from malloc(). It's not "actual
memory" to C user code. You asked for a zero-byte object, and you got a
zero-byte object, so in theory you've allocated zero bytes.

OTOH, it's certainly "actual memory" to the implementation, since
malloc() does need to request memory from the OS (or wherever) to store
the header, but that header isn't part of a C object as far as user code
can tell.

S
 
C

Chris Dollin

CBFalconer said:
Chris Dollin wrote:

No it couldn't. Think about pointer comparisons. Then think about
what other anomalies could exist. But one is enough to show it is
a bad idea.

I'm thinking, but I can't see an anomaly. I'm probably just being
dim.
 
C

CBFalconer

Keith said:
.... snip ...

Yes, I am.

Not so. The standard requires malloced pointers to objects be
distinct. After the free(p) p is no longer a pointer to an object.

--
If you want to post a followup via groups.google.com, ensure
you quote enough for the article to make sense. Google is only
a poor interface to usenet. There is no reason to assume your
readers can, or ever will, see any previous articles.
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
Y

Yevgen Muntyan

CBFalconer said:
Random832 wrote:

... snip ...



p1 = malloc(0); p2 = malloc(0); p2 = realloc(p2, 100);

(Ignore the misuse of realloc). Now, if p2 had free space above
it, p2 might be unchanged. However p1 is still pointing to zero
bytes. You would get very funny results by depending on "if (p1 ==
p2)".

But p2 could also be changed. E.g. malloc and free could be

void *malloc (size_t n)
{
if (!n)
return (void*) 0xFF0909FF;
else
{
void *result = __get_me_some_memory (n);
assert (result != (void*) 0xFF0909FF);
return result;
}
}

void free (void *ptr)
{
if (ptr && ptr != (void*) 0xFF0909FF)
__free_that_memory (ptr);
}

It doesn't make much sense since standard forbids it, but what would
break if it were like this?
Your example with realloc() assumes implementation returns some sensible
pointer on malloc(0), which can actually point to some memory allocated
later, but it's not necessary.
I believe Keith Thompson's quote is what really matters here, about
non-NULL result of malloc(0) behaving the same as malloc(10) (in
particular, non-NULL pointers must be different), so all this stuff
doesn't matter in practice though :)

Best regards,
Yevgen
 
R

Random832

2006-12-19 said:
The standard requires malloced pointers to objects be
distinct. After the free(p) p is no longer a pointer to an object.

In what sense is the non-null result of malloc(0) a pointer to an object
anyway?
 
C

Chris Torek

I'm thinking, but I can't see an anomaly. I'm probably just being
dim.

Since malloc() is a reserved function name, let me illustrate with
a different function-name. This also lets me use malloc() for the
"hard parts".

#include <stdlib.h>

static char magic;

void *nalloc(size_t size) {
if (size == 0)
return &magic; /* or: return NULL */
return malloc(size);
}

void nfree(void *p) {
if (p != &magic)
free(p);
}

void nrealloc(void *p, size_t size) {
if (p == &magic)
p = NULL;
if (size == 0) {
free(p);
return &magic; /* or: return NULL */
}
return realloc(p, size);
}

Given the obvious preconditions, the behavior of this code is
well-defined (which may suffice to label it "sensible"), but would
it suffice to replicate the Standard's requirements for malloc()?

I believe the answer is "no":

/* insert appropriate #include lines, etc., as needed */

#define Xalloc nalloc /* or malloc */
#define NAME "nalloc" /* or "malloc" */
#define Xfree nfree /* or free */

void check_it(void) {
void *p1 = Xalloc(0);
void *p2 = Xalloc(0);

if (p1 == NULL && p2 == NULL)
puts("OK: " NAME "(0) returned NULL each time");
else if (p1 == p2)
puts("FAIL: p1 == p2, but p1 and p2 are not NULL");
else {
puts("OK: alloc(0), called twice, returned two different")
puts("non-NULLs, or one non-NULL and one NULL");
}
Xfree(p1);
Xfree(p2);
}

If we use this check_it() routine on nalloc(), it will print the
"FAIL" line, because p1 and p2 are equal, yet at least one of the
two pointers is not NULL (in fact both point to the "magic" byte).

What if we replace the "return &magic" lines with "return NULL"?
Then I believe nalloc() satisfies the requirements for malloc().

Note that if one modifies check_it() -- or rather, the variant of
check_it() that uses malloc() -- to call free() on either p1 or p2
before testing their values, the check_it() function itself becomes
invalid: an attempt to use the value of a non-NULL pointer variable
that was once valid, but has since been passed to free(), causes
undefined behavior (<http://web.torek.net/torek/c/numbers2.html>).
 
C

CBFalconer

Random832 said:
In what sense is the non-null result of malloc(0) a pointer to an
object anyway?

In the sense that it behaves that way. However you can't legally
dereference it, just as you can't alter an anonymous char string.
 

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

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,269
Latest member
vinaykumar_nevatia23

Latest Threads

Top