Discussion:
what malloc(0) should returns?
(too old to reply)
q***@yahoo.com
2006-12-18 15:20:53 UTC
Permalink
Hi,
Sorry if it might be a stupid question but what should returns
malloc(0) ?

void *ptr = malloc(0);

I am running gcc 3.3.5 and a non-null address is returned.

( in the compiler that I am currently implementing, NULL is returned.
Is it wrong ?)

or does an address should be always returned and
correspond to the current heap pointer ?
Richard Heathfield
2006-12-18 15:41:27 UTC
Permalink
Post by q***@yahoo.com
Hi,
Sorry if it might be a stupid question but what should returns
malloc(0) ?
void *ptr = malloc(0);
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.

Be careful, though - at least one implementation (C/370) used to (and may
still) be non-conforming for malloc(0) - the program would abend on such a
call.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Christopher Benson-Manica
2006-12-18 15:45:04 UTC
Permalink
Post by q***@yahoo.com
Sorry if it might be a stupid question but what should returns
malloc(0) ?
7.20.3 (n869):

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.
Post by q***@yahoo.com
I am running gcc 3.3.5 and a non-null address is returned.
As it is allowed to do.
Post by q***@yahoo.com
( in the compiler that I am currently implementing, NULL is returned.
Is it wrong ?)
No.
--
C. Benson Manica | I *should* know what I'm talking about - if I
cbmanica(at)gmail.com | don't, I need to know. Flames welcome.
Jack Klein
2006-12-18 15:45:41 UTC
Permalink
Post by q***@yahoo.com
Hi,
Sorry if it might be a stupid question but what should returns
malloc(0) ?
void *ptr = malloc(0);
I am running gcc 3.3.5 and a non-null address is returned.
( in the compiler that I am currently implementing, NULL is returned.
Is it wrong ?)
or does an address should be always returned and
correspond to the current heap pointer ?
Section 7.20.3 of the current C standard states in part:

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

So either behavior is correct, but your compiler's documentation needs
to document which choice it makes.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
David T. Ashley
2006-12-18 15:48:59 UTC
Permalink
Post by q***@yahoo.com
Sorry if it might be a stupid question but what should returns
malloc(0) ?
I tried it on my Linux system:

[***@pamc ~]$ cat malloc_test.c;./a.out
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
char *p = malloc(0);

printf("%p\n", p);
}

0x9f5a008

To me personally it makes more sense if malloc(0) returns non-NULL to keep
consistency with realloc()'s behavior with 0.

Interesting thread. I did not know this was implementation-dependent.
Laurent Deniau
2006-12-18 15:57:30 UTC
Permalink
Post by David T. Ashley
Post by q***@yahoo.com
Sorry if it might be a stupid question but what should returns
malloc(0) ?
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *p = malloc(0);
printf("%p\n", p);
}
0x9f5a008
To me personally it makes more sense if malloc(0) returns non-NULL to keep
consistency with realloc()'s behavior with 0.
realloc on a null pointer must behave like malloc. So it is also
consistent if malloc(0) returns a null pointer.

a+, ld.
Richard Heathfield
2006-12-18 16:29:02 UTC
Permalink
Post by David T. Ashley
I did not know this was implementation-dependent.
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.
+++

I can't find Borland's IDB docs right now. Probably lurking in a cupboard
somewhere. Nor was I successful in tracking down the corresponding docs for
glibc. (sigh)
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
CBFalconer
2006-12-18 20:37:45 UTC
Permalink
Post by Richard Heathfield
Post by David T. Ashley
I did not know this was implementation-dependent.
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.
+++
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.
+++
I can't find Borland's IDB docs right now. Probably lurking in a
cupboard somewhere. Nor was I successful in tracking down the
corresponding docs for glibc. (sigh)
That provision leads to problems in detecting run-time allocation
errors without all sorts of special wrappers. For this (and other)
reasons I designed my nmalloc [1] to always return a valid
pointer. This is done by simply insisting on allocating at least
one byte. I don't like the idea of:

void *xgetmem(size_t sz) {
void *p;
if (NULL == (p = malloc(sz))) exit(EXIT_FAILURE);
return p;
}

aborting when called with the argument 0. I think reserving NULL
returns for real failures is a QofI matter. In this case I think
Microsoft actually did the right thing.

[1] <http://cbfalconer.home.att.net/download/>
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Keith Thompson
2006-12-18 22:51:42 UTC
Permalink
Post by Richard Heathfield
Post by David T. Ashley
I did not know this was implementation-dependent.
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.
+++
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory. Based on the wording of the standard, I would
expect successive calls to malloc(0) (assuming it doesn't return a
null pointer value) to return distinct values.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Ben Pfaff
2006-12-18 23:07:12 UTC
Permalink
Post by Keith Thompson
Post by Richard Heathfield
+++
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory. [...]
Some systems have a class of pointers that can't be dereferenced
but won't trap. For example, under Linux on x86 you could
normally use any pointer with value 0xc0000000 (as seen when cast
to uintptr_t) or greater as such. As long as you didn't need
more than about a billion of them, you could just use a counter
to keep track of how many you'd given out. Once you ran out, you
could fall back to treating malloc(0) as malloc(1) or just
returning a null pointer.

(I don't know how Linux system calls would react to such a
pointer. Probably unhappily.)
--
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
Random832
2006-12-19 00:14:48 UTC
Permalink
Post by Ben Pfaff
Post by Keith Thompson
Post by Richard Heathfield
+++
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory. [...]
Some systems have a class of pointers that can't be dereferenced
but won't trap. For example, under Linux on x86 you could
normally use any pointer with value 0xc0000000 (as seen when cast
to uintptr_t) or greater as such. As long as you didn't need
more than about a billion of them, you could just use a counter
to keep track of how many you'd given out. Once you ran out, you
could fall back to treating malloc(0) as malloc(1) or just
returning a null pointer.
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.
Post by Ben Pfaff
(I don't know how Linux system calls would react to such a
pointer. Probably unhappily.)
Standard procedure on receiving an invalid pointer is to return -EINVAL
[which the library changes to an appropriate failure return and errno
EINVAL]
Keith Thompson
2006-12-19 01:06:08 UTC
Permalink
Random832 <***@random.yi.org> writes:
[...]
Post by Random832
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.
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).

The simplest way to implement this is to quietly translate "malloc(0)"
to "malloc(1)".
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jack Klein
2006-12-19 03:28:53 UTC
Permalink
Post by Keith Thompson
[...]
Post by Random832
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.
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).
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.
Post by Keith Thompson
The simplest way to implement this is to quietly translate "malloc(0)"
to "malloc(1)".
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
Keith Thompson
2006-12-19 05:50:41 UTC
Permalink
Post by Jack Klein
Post by Keith Thompson
[...]
Post by Random832
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.
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).
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?
Um, C99 7.20.3p1?
Post by Jack Klein
Is there any reason why, in a suitable function with a suitable
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.
Post by Jack Klein
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.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
trm
2006-12-19 15:20:28 UTC
Permalink
Post by Keith Thompson
Post by Jack Klein
Is there any reason why, in a suitable function with a
uintptr_t pu, qu;
void *p = malloc(100);
pu = (uintptr_t)p;
free (p);
^^^^^^^^
Post by Keith Thompson
Post by Jack Klein
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.
Er, I suspect this would break a lot of code...
Post by Keith Thompson
Post by Jack Klein
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().
...I believe you may have misspelled "No, I'm not" up above.
Would you mind clarifying your clarification?
Keith Thompson
2006-12-19 21:13:44 UTC
Permalink
Post by trm
Post by Keith Thompson
Post by Jack Klein
Is there any reason why, in a suitable function with a
uintptr_t pu, qu;
void *p = malloc(100);
pu = (uintptr_t)p;
free (p);
^^^^^^^^
Post by Keith Thompson
Post by Jack Klein
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.
And I was wrong.
Post by trm
Er, I suspect this would break a lot of code...
It would break a lot of implementations, but it shouldn't break much
code; well-written code shouldn't *care* about the values of free()d
pointers.
Post by trm
Post by Keith Thompson
Post by Jack Klein
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().
...I believe you may have misspelled "No, I'm not" up above.
Would you mind clarifying your clarification?
I missed the free() call. Certainly an implementation can re-use
free()d addresses.

What I *meant* to assert is that, for example, the following:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void *p1 = malloc(0);
void *p2 = malloc(0);
if (p1 == NULL || p2 == NULL || p1 != p2) {
puts("ok");
}
else {
puts("oops");
}
return 0;
}

must always print "ok".

Note that if malloc(0) returns a null pointer, it can be either
because the implementation always does that, or because there's not
enough available memory.

In my opinion, the behavior defined by the standard for malloc(0) is
not particularly useful.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Stephen Sprunk
2006-12-19 23:50:57 UTC
Permalink
Post by Keith Thompson
In my opinion, the behavior defined by the standard for malloc(0) is
not particularly useful.
As with many C oddities, it was more an issue of documenting what
existing pre-ANSI C implementations did, not specifying ideal behavior.

A lot of things in C would be very different if it had been specified
fully before implementations were written -- but it never would have
caught on.

S
--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
--
Posted via a free Usenet account from http://www.teranews.com
Keith Thompson
2006-12-20 05:05:27 UTC
Permalink
Post by Stephen Sprunk
Post by Keith Thompson
In my opinion, the behavior defined by the standard for malloc(0) is
not particularly useful.
As with many C oddities, it was more an issue of documenting what
existing pre-ANSI C implementations did, not specifying ideal behavior.
A lot of things in C would be very different if it had been specified
fully before implementations were written -- but it never would have
caught on.
Agreed. I think the gist of the description is that malloc(0) isn't
allowed to blow up; the standard goes into some (possibly unnecessary)
detail about *how* it's not allowed to blow up.

But it seems to me the C89 standard *could* have nailed this down more
tightly than it did. It also mandated that free(NULL) does nothing;
in some existing implementations at the time, it would crash.
Mandating that malloc(0) returns a unique non-null pointer (unless
memory has run out) would have been just as easy; implementations
would just have had to change to meet the new requirement.

It's too late now, I suppose.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
CBFalconer
2006-12-19 15:50:30 UTC
Permalink
... snip ...
Post by Keith Thompson
Post by Jack Klein
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.
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/>
Random832
2006-12-19 17:47:21 UTC
Permalink
Post by CBFalconer
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?
CBFalconer
2006-12-19 20:19:30 UTC
Permalink
Post by Random832
Post by CBFalconer
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?
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.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Random832
2006-12-19 21:44:43 UTC
Permalink
Post by CBFalconer
Post by Random832
Post by CBFalconer
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?
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.
To what object does it point?
Harald van Dijk
2006-12-19 22:17:18 UTC
Permalink
Post by Random832
Post by CBFalconer
Post by Random832
Post by CBFalconer
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?
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.
To what object does it point?
It doesn't have a name, just as the result of malloc(sizeof(int))
doesn't have a name.

An object is defined as "region of data storage in the execution
environment, the contents of which can represent values". Since
malloc(0) must (if it doesn't return NULL) behave as if a positive
argument is passed, except for dereferencing, you still get a pointer
to a region. In particular, if you convert malloc's result to a
character pointer, it means you're allowed to increment it at least
once. The fact that you're not allowed to access the value is
irrelevant, since the definition doesn't state otherwise.
CBFalconer
2006-12-19 22:37:12 UTC
Permalink
Post by Harald van Dijk
Post by Random832
Post by CBFalconer
Post by Random832
Post by CBFalconer
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?
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.
To what object does it point?
It doesn't have a name, just as the result of malloc(sizeof(int))
doesn't have a name.
An object is defined as "region of data storage in the execution
environment, the contents of which can represent values". Since
malloc(0) must (if it doesn't return NULL) behave as if a positive
argument is passed, except for dereferencing, you still get a pointer
to a region. In particular, if you convert malloc's result to a
character pointer, it means you're allowed to increment it at least
once. The fact that you're not allowed to access the value is
irrelevant, since the definition doesn't state otherwise.
Since it points to zero storage bytes, it has already been
incremented to one past the storage area.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Ben Pfaff
2006-12-19 23:26:27 UTC
Permalink
Post by CBFalconer
Post by Harald van Dijk
Since
malloc(0) must (if it doesn't return NULL) behave as if a positive
argument is passed, except for dereferencing, you still get a pointer
to a region. In particular, if you convert malloc's result to a
character pointer, it means you're allowed to increment it at least
once. The fact that you're not allowed to access the value is
irrelevant, since the definition doesn't state otherwise.
Since it points to zero storage bytes, it has already been
incremented to one past the storage area.
No, it points to at least one byte. It's just that that byte, or
those bytes, cannot be accessed. The standard is quite clear
about this:

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.

I, at least, don't think that incrementing a pointer is
"access[ing] an object". Do you?
--
"When I have to rely on inadequacy, I prefer it to be my own."
--Richard Heathfield
Simon Biber
2006-12-19 23:23:17 UTC
Permalink
Post by Harald van Dijk
An object is defined as "region of data storage in the execution
environment, the contents of which can represent values". Since
malloc(0) must (if it doesn't return NULL) behave as if a positive
argument is passed, except for dereferencing, you still get a pointer
to a region. In particular, if you convert malloc's result to a
character pointer, it means you're allowed to increment it at least
once. The fact that you're not allowed to access the value is
irrelevant, since the definition doesn't state otherwise.
Are you sure that you're allowed to increment it? I think that's unclear
from the C standard's wording:

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

It does not merely say that the returned pointer shall not be
dereferenced. It says that it shall not be used to access an object. If
you convert the pointer to char* and increment it, that action is only
valid if there is an object of at least one byte at the address. So it
could be argued that in effect you have used the pointer to access an
object.
--
Simon.
Ben Pfaff
2006-12-19 23:29:18 UTC
Permalink
If you convert the pointer to char* and increment it, that
action is only valid if there is an object of at least one byte at the
address. So it could be argued that in effect you have used the
pointer to access an object.
The standard defines "access" like this:

3.1
1 access
execution-time action to read or modify the value of an object

Incrementing a pointer does not read or modify the value of the
object that the pointer points to (unless the pointer points to
itself, but that's not the case here).
--
"In My Egotistical Opinion, most people's C programs should be indented six
feet downward and covered with dirt." -- Blair P. Houghton
Stephen Sprunk
2006-12-19 23:56:42 UTC
Permalink
Post by Random832
Post by CBFalconer
Post by Random832
Post by CBFalconer
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?
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.
To what object does it point?
To the zero-byte object that malloc() allocated :)

Of course, asking for details about a zero-byte object is pointless,
since an object of zero bytes has no properties other than an address.
It's like asking about properties of a object of type void (and I don't
mean void*).

Harald's comment about being able to increment a pointer to a zero-byte
object is interesting, though. Should that be legal? IMHO, the pointer
already points to the byte after the end of the object when you get it,
and it'd be UB to try to increment it -- or decrement it.

S
--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
--
Posted via a free Usenet account from http://www.teranews.com
Keith Thompson
2006-12-20 04:59:58 UTC
Permalink
Post by Stephen Sprunk
Post by Random832
Post by CBFalconer
Post by Random832
Post by CBFalconer
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?
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.
To what object does it point?
To the zero-byte object that malloc() allocated :)
No, to the at-least-one-byte object that malloc() allocated (but that
you're not allowed to access).
Post by Stephen Sprunk
Of course, asking for details about a zero-byte object is pointless,
since an object of zero bytes has no properties other than an
address. It's like asking about properties of a object of type void
(and I don't mean void*).
There are no objects of type void.
Post by Stephen Sprunk
Harald's comment about being able to increment a pointer to a
zero-byte object is interesting, though. Should that be legal? IMHO,
the pointer already points to the byte after the end of the object
when you get it, and it'd be UB to try to increment it -- or decrement
it.
C doesn't support zero-byte objects.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Serve Laurijssen
2006-12-19 21:11:57 UTC
Permalink
Post by CBFalconer
Post by Keith Thompson
Post by Jack Klein
...are you claiming that pu and qu must compare unequal because
they were returned by successive calls to malloc()?
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.
I think keith missed the free because he says later "assuming there are no
intervening calls to free()"
Keith Thompson
2006-12-19 21:14:59 UTC
Permalink
Post by CBFalconer
... snip ...
Post by Keith Thompson
Post by Jack Klein
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.
Not so. The standard requires malloced pointers to objects be
distinct. After the free(p) p is no longer a pointer to an object.
Quite correct; I missed the call to free().
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
WaterWalk
2006-12-20 01:07:48 UTC
Permalink
*sniped* <
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).
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).
The simplest way to implement this is to quietly translate "malloc(0)"
to "malloc(1)".
Does this imply that if an implementation makes malloc(0) return a
non-null pointer, this pointer shall be free()d?
CBFalconer
2006-12-20 02:02:13 UTC
Permalink
Post by WaterWalk
*sniped* <
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).
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).
The simplest way to implement this is to quietly translate
"malloc(0)" to "malloc(1)".
Does this imply that if an implementation makes malloc(0) return
a non-null pointer, this pointer shall be free()d?
Yes. Implied by the fact that the malloc subsystem has to keep
track of allocations somewhere, and this necessarily consumes some
sort of storage. free then releases any such.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Keith Thompson
2006-12-20 05:07:18 UTC
Permalink
Post by WaterWalk
*sniped* <
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).
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).
The simplest way to implement this is to quietly translate "malloc(0)"
to "malloc(1)".
Does this imply that if an implementation makes malloc(0) return a
non-null pointer, this pointer shall be free()d?
What do you mean by "shall"?

There's no requirement to free() any malloc()ed pointer; terminating a
program without free()ing anything is perfectly acceptable as far as
the standard is concerned.

It's true that the result returned by malloc(0) *may* be passed to
free().
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
WaterWalk
2006-12-24 12:24:57 UTC
Permalink
Post by Keith Thompson
Post by WaterWalk
*sniped* <
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).
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).
The simplest way to implement this is to quietly translate "malloc(0)"
to "malloc(1)".
Does this imply that if an implementation makes malloc(0) return a
non-null pointer, this pointer shall be free()d?
What do you mean by "shall"?
There's no requirement to free() any malloc()ed pointer; terminating a
program without free()ing anything is perfectly acceptable as far as
the standard is concerned.
It's true that the result returned by malloc(0) *may* be passed to
free().
Oh, what I mean is: if a lot of malloc(0) is called and the returned
results are not free()d, then this is still memory leak. Am I right?
Harald van Dijk
2006-12-24 13:58:18 UTC
Permalink
Post by WaterWalk
Post by Keith Thompson
Post by WaterWalk
Does this imply that if an implementation makes malloc(0) return a
non-null pointer, this pointer shall be free()d?
What do you mean by "shall"?
There's no requirement to free() any malloc()ed pointer; terminating a
program without free()ing anything is perfectly acceptable as far as
the standard is concerned.
It's true that the result returned by malloc(0) *may* be passed to
free().
Oh, what I mean is: if a lot of malloc(0) is called and the returned
results are not free()d, then this is still memory leak. Am I right?
Yes, if you do not free a non-NULL result from malloc, even with a size
of zero, you have a memory leak.
CBFalconer
2006-12-24 15:39:26 UTC
Permalink
Post by Harald van Dijk
Post by WaterWalk
Post by Keith Thompson
Post by WaterWalk
Does this imply that if an implementation makes malloc(0) return
a non-null pointer, this pointer shall be free()d?
What do you mean by "shall"?
There's no requirement to free() any malloc()ed pointer;
terminating a program without free()ing anything is perfectly
acceptable as far as the standard is concerned.
It's true that the result returned by malloc(0) *may* be passed
to free().
Oh, what I mean is: if a lot of malloc(0) is called and the
returned results are not free()d, then this is still memory leak.
Am I right?
Yes, if you do not free a non-NULL result from malloc, even with
a size of zero, you have a memory leak.
If you stop to think about it the system has to keep track of
allocations somewhere, even in the case of a zero size returning
non-NULL, and the only way to signal the release of that
information is via free.
--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Joe Wright
2006-12-24 17:10:26 UTC
Permalink
Post by CBFalconer
Post by Harald van Dijk
Post by WaterWalk
Post by Keith Thompson
Post by WaterWalk
Does this imply that if an implementation makes malloc(0) return
a non-null pointer, this pointer shall be free()d?
What do you mean by "shall"?
There's no requirement to free() any malloc()ed pointer;
terminating a program without free()ing anything is perfectly
acceptable as far as the standard is concerned.
It's true that the result returned by malloc(0) *may* be passed
to free().
Oh, what I mean is: if a lot of malloc(0) is called and the
returned results are not free()d, then this is still memory leak.
Am I right?
Yes, if you do not free a non-NULL result from malloc, even with
a size of zero, you have a memory leak.
If you stop to think about it the system has to keep track of
allocations somewhere, even in the case of a zero size returning
non-NULL, and the only way to signal the release of that
information is via free.
Hi Chuck. Merry Christmas.

If I were King, the argument to malloc would be defined > 0. An argument
0 would force a malloc failure and a NULL return. free(NULL) is harmless
and so, voila, no problem.
--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
CBFalconer
2006-12-24 18:07:02 UTC
Permalink
... snip ...
Post by Joe Wright
Post by CBFalconer
If you stop to think about it the system has to keep track of
allocations somewhere, even in the case of a zero size returning
non-NULL, and the only way to signal the release of that
information is via free.
If I were King, the argument to malloc would be defined > 0.
An argument 0 would force a malloc failure and a NULL return.
free(NULL) is harmless and so, voila, no problem.
Bad idea. The system may be used to process variable length data,
which may be empty. This size can be coming in as a parameter to
some routine or other. You don't want to have to test all sorts of
special cases in that routine. Although with the existing C
standard you probably have to:

if (!sz) sz++;
if (!(p = malloc(sz)) failure();
else carryon();

which is why I consider systems that return distinct pointers for
malloc(0) superior. They will forgive forgetting to make the
preliminary check.
--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Keith Thompson
2006-12-24 19:33:24 UTC
Permalink
Post by CBFalconer
... snip ...
Post by Joe Wright
Post by CBFalconer
If you stop to think about it the system has to keep track of
allocations somewhere, even in the case of a zero size returning
non-NULL, and the only way to signal the release of that
information is via free.
If I were King, the argument to malloc would be defined > 0.
An argument 0 would force a malloc failure and a NULL return.
free(NULL) is harmless and so, voila, no problem.
Bad idea. The system may be used to process variable length data,
which may be empty. This size can be coming in as a parameter to
some routine or other. You don't want to have to test all sorts of
special cases in that routine. Although with the existing C
if (!sz) sz++;
if (!(p = malloc(sz)) failure();
else carryon();
which is why I consider systems that return distinct pointers for
malloc(0) superior. They will forgive forgetting to make the
preliminary check.
In other words, they will fail to diagnose the failure to make the
required check. How friendly.

If I were King, the behavior of malloc(0) would be well-defined. I
might flip a coin to decide *how* it's defined. Heads (i.e., my
portrait) means it's equivalent to malloc(1), except that the pointer
may not be dereferenced; tails means malloc(0) returns a null pointer.
The coin toss would occur only once, and would determine the rule to
be written in the standard. Sufficient bribery might induce me to use
a weighted coin.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
P.J. Plauger
2006-12-25 00:23:42 UTC
Permalink
Post by Keith Thompson
Post by CBFalconer
... snip ...
Post by Joe Wright
Post by CBFalconer
If you stop to think about it the system has to keep track of
allocations somewhere, even in the case of a zero size returning
non-NULL, and the only way to signal the release of that
information is via free.
If I were King, the argument to malloc would be defined > 0.
An argument 0 would force a malloc failure and a NULL return.
free(NULL) is harmless and so, voila, no problem.
Bad idea. The system may be used to process variable length data,
which may be empty. This size can be coming in as a parameter to
some routine or other. You don't want to have to test all sorts of
special cases in that routine. Although with the existing C
if (!sz) sz++;
if (!(p = malloc(sz)) failure();
else carryon();
which is why I consider systems that return distinct pointers for
malloc(0) superior. They will forgive forgetting to make the
preliminary check.
In other words, they will fail to diagnose the failure to make the
required check. How friendly.
If I were King, the behavior of malloc(0) would be well-defined. I
might flip a coin to decide *how* it's defined. Heads (i.e., my
portrait) means it's equivalent to malloc(1), except that the pointer
may not be dereferenced; tails means malloc(0) returns a null pointer.
The coin toss would occur only once, and would determine the rule to
be written in the standard. Sufficient bribery might induce me to use
a weighted coin.
But what happened instead was much worse. I fought for several meetings
to have malloc(0) return a unique non-null pointer -- just as the Unix
implementation had been doing since day one, not to mention ours (then
Whitesmiths) and all others I knew about. As CBFalconer observed, a
zero-size dynamic array is a naturally occuring thing, just like while
loops that loop zero times. But for some reason Larry Rosler argued
vehemently for malloc(0) being an error, even though this was not in
the best interests of Bell Labs, his employer. By the time I'd convinced
Rosler of my view, most of the committee had grown tired of the whole
debate. So they settled on the worst possible "compromise" -- neither
behavior is guaranteed.

A coin toss would have been a better resolution.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
CBFalconer
2006-12-25 01:39:21 UTC
Permalink
"P.J. Plauger" wrote:
... snip ...
Post by P.J. Plauger
But what happened instead was much worse. I fought for several meetings
to have malloc(0) return a unique non-null pointer -- just as the Unix
implementation had been doing since day one, not to mention ours (then
Whitesmiths) and all others I knew about. As CBFalconer observed, a
zero-size dynamic array is a naturally occuring thing, just like while
loops that loop zero times. But for some reason Larry Rosler argued
vehemently for malloc(0) being an error, even though this was not in
the best interests of Bell Labs, his employer. By the time I'd convinced
Rosler of my view, most of the committee had grown tired of the whole
debate. So they settled on the worst possible "compromise" -- neither
behavior is guaranteed.
A coin toss would have been a better resolution.
Well, at least now we can point disdainfully at the actual cause of
the problem :-) We can name it the Rosler curse.

BTW, to answer Keiths objection, my nmalloc for DJGPP includes a
provision (non-standard) for injecting run-time hooks, which can
change that behaviour.
--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Richard Tobin
2006-12-25 12:17:05 UTC
Permalink
Post by P.J. Plauger
So they settled on the worst possible "compromise" -- neither
behavior is guaranteed.
I agree distinct pointers would be better, but the current behaviour
does at least cover the common case: you can malloc an array without
regard for it being possibly empty, and realloc it safely, getting a
real unique value once you need some real memory.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
P.J. Plauger
2006-12-25 14:03:43 UTC
Permalink
Post by Richard Tobin
Post by P.J. Plauger
So they settled on the worst possible "compromise" -- neither
behavior is guaranteed.
I agree distinct pointers would be better, but the current behaviour
does at least cover the common case: you can malloc an array without
regard for it being possibly empty, and realloc it safely, getting a
real unique value once you need some real memory.
Uh, no. One of the arguments in favor of permitting malloc(0) to be
erroneous was to let some systems diagnose, even trap out, on such
a call. So it's never portably safe to call malloc(0), and it's never
a sure thing that it'll be treated as an error. Everybody loses.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
Richard Tobin
2006-12-25 15:44:07 UTC
Permalink
Post by P.J. Plauger
Post by Richard Tobin
I agree distinct pointers would be better, but the current behaviour
does at least cover the common case: you can malloc an array without
regard for it being possibly empty, and realloc it safely, getting a
real unique value once you need some real memory.
Uh, no. One of the arguments in favor of permitting malloc(0) to be
erroneous was to let some systems diagnose, even trap out, on such
a call. So it's never portably safe to call malloc(0), and it's never
a sure thing that it'll be treated as an error. Everybody loses.
I think you're misremembering. The standard requires malloc(0) to
return either a distinct pointer or NULL. It's not allowed to treat
it as an error.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
P.J. Plauger
2006-12-25 16:33:31 UTC
Permalink
Post by Richard Tobin
Post by P.J. Plauger
Post by Richard Tobin
I agree distinct pointers would be better, but the current behaviour
does at least cover the common case: you can malloc an array without
regard for it being possibly empty, and realloc it safely, getting a
real unique value once you need some real memory.
Uh, no. One of the arguments in favor of permitting malloc(0) to be
erroneous was to let some systems diagnose, even trap out, on such
a call. So it's never portably safe to call malloc(0), and it's never
a sure thing that it'll be treated as an error. Everybody loses.
I think you're misremembering. The standard requires malloc(0) to
return either a distinct pointer or NULL. It's not allowed to treat
it as an error.
So it seems. The C Standard didn't always end up saying exactly
what the committee decided by consensus.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
av
2006-12-25 16:45:54 UTC
Permalink
Post by Keith Thompson
Post by CBFalconer
... snip ...
Post by Joe Wright
Post by CBFalconer
If you stop to think about it the system has to keep track of
allocations somewhere, even in the case of a zero size returning
non-NULL, and the only way to signal the release of that
information is via free.
If I were King, the argument to malloc would be defined > 0.
An argument 0 would force a malloc failure and a NULL return.
free(NULL) is harmless and so, voila, no problem.
Bad idea. The system may be used to process variable length data,
which may be empty. This size can be coming in as a parameter to
some routine or other. You don't want to have to test all sorts of
special cases in that routine. Although with the existing C
if (!sz) sz++;
if (!(p = malloc(sz)) failure();
else carryon();
which is why I consider systems that return distinct pointers for
malloc(0) superior. They will forgive forgetting to make the
preliminary check.
In other words, they will fail to diagnose the failure to make the
required check. How friendly.
If I were King, the behavior of malloc(0) would be well-defined. I
might flip a coin to decide *how* it's defined. Heads (i.e., my
portrait) means it's equivalent to malloc(1), except that the pointer
may not be dereferenced; tails means malloc(0) returns a null pointer.
The coin toss would occur only once, and would determine the rule to
be written in the standard. Sufficient bribery might induce me to use
a weighted coin.
why standard says should be: malloc(0)==0 or malloc(0) has to point
some data whose access is illegal

why malloc(0)!=0 has to point to some data
(i.e. "(char*)malloc(0)"
has some memory, but access to it is illegal)?

in how i see
malloc(0) has to return "p" pointer
|header|
^
p
where *(char*)p has to segfault and p should not have memory reserved
for programme
av
2006-12-25 18:40:11 UTC
Permalink
Post by av
in how i see
malloc(0) has to return "p" pointer
|header|
^
p
where *(char*)p has to segfault and p should not have memory reserved
for programme
wrong (above mean each malloc(0) has its pointer different)
where *(char*)p=1 can segfault, or free() function can possibly see
the error when it free p
WaterWalk
2006-12-26 00:57:56 UTC
Permalink
Post by CBFalconer
... snip ...
Post by Joe Wright
Post by CBFalconer
If you stop to think about it the system has to keep track of
allocations somewhere, even in the case of a zero size returning
non-NULL, and the only way to signal the release of that
information is via free.
If I were King, the argument to malloc would be defined > 0.
An argument 0 would force a malloc failure and a NULL return.
free(NULL) is harmless and so, voila, no problem.
Bad idea. The system may be used to process variable length data,
which may be empty. This size can be coming in as a parameter to
some routine or other. You don't want to have to test all sorts of
special cases in that routine. Although with the existing C
if (!sz) sz++;
if (!(p = malloc(sz)) failure();
else carryon();
which is why I consider systems that return distinct pointers for
malloc(0) superior. They will forgive forgetting to make the
preliminary check.
I don't think it's a good idea. For even if sz in malloc(sz) is bigger
than zero, you still have to test if the malloc fails, since it is
always possible that not enough memory exists.
CBFalconer
2006-12-26 01:27:38 UTC
Permalink
... snip ...
Post by WaterWalk
Post by CBFalconer
Bad idea. The system may be used to process variable length data,
which may be empty. This size can be coming in as a parameter to
some routine or other. You don't want to have to test all sorts of
special cases in that routine. Although with the existing C
if (!sz) sz++;
if (!(p = malloc(sz)) failure();
else carryon();
which is why I consider systems that return distinct pointers for
malloc(0) superior. They will forgive forgetting to make the
preliminary check.
I don't think it's a good idea. For even if sz in malloc(sz) is
bigger than zero, you still have to test if the malloc fails,
since it is always possible that not enough memory exists.
I think you missed the word 'preliminary' above. That is the check
on sz.
--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Ben Pfaff
2006-12-19 01:06:57 UTC
Permalink
Post by Random832
Post by Ben Pfaff
Some systems have a class of pointers that can't be dereferenced
but won't trap. For example, under Linux on x86 you could
normally use any pointer with value 0xc0000000 (as seen when cast
to uintptr_t) or greater as such. As long as you didn't need
more than about a billion of them, you could just use a counter
to keep track of how many you'd given out. Once you ran out, you
could fall back to treating malloc(0) as malloc(1) or just
returning a null pointer.
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.
They'd better not do that (C99 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.

<off-topic xmlns="news:comp.lang.c">
Post by Random832
Post by Ben Pfaff
(I don't know how Linux system calls would react to such a
pointer. Probably unhappily.)
Standard procedure on receiving an invalid pointer is to return -EINVAL
[which the library changes to an appropriate failure return and errno
EINVAL]
That's definitely not correct: EFAULT is the POSIX error code for
"bad address". But the question is whether the kernel pays
attention to the pointer value if the associated length is 0. It
might, or it might not, or it might differ from one system call
to another.
</off-topic>
--
"Programmers have the right to be ignorant of many details of your code
and still make reasonable changes."
--Kernighan and Plauger, _Software Tools_
CBFalconer
2006-12-19 01:23:31 UTC
Permalink
Random832 wrote:
... snip ...
Post by Random832
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)".
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Chris Dollin
2006-12-19 09:01:06 UTC
Permalink
Post by CBFalconer
... snip ...
Post by Random832
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.

Wouldn't it?
--
Chris "HO. HO. HO." Dollin
"It took a very long time, much longer than the most generous estimates."
- James White, /Sector General/
Richard Bos
2006-12-19 09:44:32 UTC
Permalink
Post by CBFalconer
Post by Random832
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.
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
Chris Dollin
2006-12-19 10:00:04 UTC
Permalink
Post by Richard Bos
Post by CBFalconer
Post by Random832
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.
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?
--
Chris "HO. HO. HO." Dollin
"Who do you serve, and who do you trust?" /Crusade/
Simon Biber
2006-12-19 23:31:50 UTC
Permalink
Post by Richard Bos
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.
char *p1, *p2;
p1=malloc(0); p2=malloc(0);
p1=realloc(p1, 200);
p2=realloc(p2, 100);
p1[123]='?';
This code is fine, so long as the realloc on the third line succeeds,
otherwise the fifth line dereferences a null pointer.

If we're on an implementation that returns the same
pointer P for each malloc(0):
line 1: defines p1 and p2
line 2: p1 and p2 both gets the 'special' pointer P
line 3: realloc detects the P and returns malloc(200)
line 4: realloc detects the P and returns malloc(100)
line 5: the 124th byte of the block allocated on line 3 is set to '?'
Post by Richard Bos
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.
Absolutely not. There is no undefined behaviour. The third line modifies
the value of p1 but it does not modify the value of p2. The value of p2
may still have the special pointer P, so the fourth line behaves exactly
like the third line did.
Post by Richard Bos
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).
Faulty logic. The code has no undefined behaviour even if malloc(0) does
return the same pointer each time.
--
Simon.
CBFalconer
2006-12-19 10:27:41 UTC
Permalink
Post by CBFalconer
... snip ...
Post by Random832
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.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Chris Dollin
2006-12-19 11:48:07 UTC
Permalink
Post by CBFalconer
Post by CBFalconer
... snip ...
Post by Random832
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
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.
--
Chris "HO. HO. HO." Dollin
"Who do you serve, and who do you trust?" /Crusade/
CBFalconer
2006-12-19 14:48:29 UTC
Permalink
Post by Chris Dollin
Post by CBFalconer
Post by CBFalconer
... snip ...
Post by Random832
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
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.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Chris Dollin
2006-12-19 15:41:14 UTC
Permalink
Post by CBFalconer
Post by Chris Dollin
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.
I'm thinking, but I can't see an anomaly. I'm probably just being
dim.
--
Chris "HO. HO. HO." Dollin
Meaning precedes definition.
CBFalconer
2006-12-19 16:39:43 UTC
Permalink
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
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.
I'm thinking, but I can't see an anomaly. I'm probably just being
dim.
You snipped one that I showed earlier.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Chris Dollin
2006-12-20 08:47:11 UTC
Permalink
Post by CBFalconer
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
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.
I'm thinking, but I can't see an anomaly. I'm probably just being
dim.
You snipped one that I showed earlier.
Hell's teeth, man, cut me some slack -- it's nearly Christmas. I
/did not see/ an anomaly. Write the thing in a reply and explain
what the problem is. It's probably too obvious for me to be able
to see it without help.
--
Chris "HO. HO. HO." Dollin
Nit-picking is best done among friends.
CBFalconer
2006-12-20 13:41:54 UTC
Permalink
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
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.
I'm thinking, but I can't see an anomaly. I'm probably just being
dim.
You snipped one that I showed earlier.
Hell's teeth, man, cut me some slack -- it's nearly Christmas. I
/did not see/ an anomaly. Write the thing in a reply and explain
what the problem is. It's probably too obvious for me to be able
to see it without help.
<Requoted>
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
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)".
</requoted>

The anomaly appears if the results of the malloc calls are non-NULL
and not distinct, i.e. non-compliant.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Random832
2006-12-20 15:45:06 UTC
Permalink
Post by CBFalconer
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
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.
I'm thinking, but I can't see an anomaly. I'm probably just being
dim.
You snipped one that I showed earlier.
Hell's teeth, man, cut me some slack -- it's nearly Christmas. I
/did not see/ an anomaly. Write the thing in a reply and explain
what the problem is. It's probably too obvious for me to be able
to see it without help.
<Requoted>
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
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.
Or it might NOT be unchanged, since we've established that in the
implementation method being discussed, malloc(0) is a special case and
not a normal heap pointer.
Post by CBFalconer
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
However p1 is still pointing to zero
bytes. You would get very funny results by depending on "if
(p1 == p2)".
</requoted>
The anomaly appears if the results of the malloc calls are non-NULL
and not distinct, i.e. non-compliant.
Chris Torek
2006-12-19 20:16:34 UTC
Permalink
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
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.
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>).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Simon Biber
2006-12-19 23:44:38 UTC
Permalink
Post by Chris Torek
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);
}
Looks good, except that nrealloc should return void *.
Post by Chris Torek
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()?
/* 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).
Yes. Though if there weren't the explicit restriction in the standard:
"Each such allocation shall yield a pointer to an object disjoint
from any other object."
Then this behaviour of nalloc would be acceptable as a replacement for
malloc.
--
Simon.
Random832
2006-12-20 00:38:32 UTC
Permalink
Post by Simon Biber
Post by Chris Torek
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);
}
Looks good, except that nrealloc should return void *.
Post by Chris Torek
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()?
/* 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).
"Each such allocation shall yield a pointer to an object disjoint
from any other object."
All zero-length objects are disjoint from one another. Or at least as
many as the number of angels that can dance on the head of a pin.
Post by Simon Biber
Then this behaviour of nalloc would be acceptable as a replacement for
malloc.
Chris Dollin
2006-12-20 08:56:25 UTC
Permalink
Post by Chris Torek
Post by Chris Dollin
Post by CBFalconer
Post by Chris Dollin
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.
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".
(fx:snip)
Post by Chris Torek
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()?
No, because the Standard says otherwise -- but CB seemed to be
arguing that even without that explicit requirement the unique
magic pointer approach couldn't be made consistent.
--
Chris "HO. HO. HO." Dollin
"I'm still here and I'm holding the answers" - Karnataka, /Love and Affection/
Yevgen Muntyan
2006-12-19 17:23:01 UTC
Permalink
Post by CBFalconer
... snip ...
Post by Random832
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)".
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
CBFalconer
2006-12-19 20:22:25 UTC
Permalink
Post by Yevgen Muntyan
Post by CBFalconer
... snip ...
Post by Random832
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)".
But p2 could also be changed. E.g. malloc and free could be
Please don't send email copies of usenet articles. It is just
further clutter and annoyance at this end.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Stephen Sprunk
2006-12-18 23:13:49 UTC
Permalink
Post by Keith Thompson
Post by Richard Heathfield
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory. Based on the wording of the standard, I would
expect successive calls to malloc(0) (assuming it doesn't return a
null pointer value) to return distinct values.
A common implementation of malloc() writes a header (containing links
between blocks, size of the user object, and possibly a magic value to
detect corruption) regardless of allocation size. The value returned to
the user is the address *after* the header.

In the case of malloc(0), the header is immediately followed by the next
header (or a trailer with a magic value to detect corruption, then the
next header). Therefore, successive calls will return different
addresses, since each new header starts at a different address. Do it
enough times and you can run out of heap space even though you're
theoretically allocating no memory :)

S
--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
--
Posted via a free Usenet account from http://www.teranews.com
Keith Thompson
2006-12-18 23:56:44 UTC
Permalink
Post by Stephen Sprunk
Post by Keith Thompson
Post by Richard Heathfield
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory. Based on the wording of the standard, I would
expect successive calls to malloc(0) (assuming it doesn't return a
null pointer value) to return distinct values.
A common implementation of malloc() writes a header (containing links
between blocks, size of the user object, and possibly a magic value to
detect corruption) regardless of allocation size. The value returned
to the user is the address *after* the header.
In the case of malloc(0), the header is immediately followed by the
next header (or a trailer with a magic value to detect corruption,
then the next header). Therefore, successive calls will return
different addresses, since each new header starts at a different
address. Do it enough times and you can run out of heap space even
though you're theoretically allocating no memory :)
So the memory allocated for the header isn't "actual memory"?
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Stephen Sprunk
2006-12-19 15:30:31 UTC
Permalink
Post by Keith Thompson
Post by Stephen Sprunk
Post by Keith Thompson
Post by Richard Heathfield
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory. Based on the wording of the standard, I would
expect successive calls to malloc(0) (assuming it doesn't return a
null pointer value) to return distinct values.
A common implementation of malloc() writes a header (containing links
between blocks, size of the user object, and possibly a magic value to
detect corruption) regardless of allocation size. The value returned
to the user is the address *after* the header.
In the case of malloc(0), the header is immediately followed by the
next header (or a trailer with a magic value to detect corruption,
then the next header). Therefore, successive calls will return
different addresses, since each new header starts at a different
address. Do it enough times and you can run out of heap space even
though you're theoretically allocating no memory :)
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
--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
--
Posted via a free Usenet account from http://www.teranews.com
Kohn Emil Dan
2006-12-18 23:48:12 UTC
Permalink
<snipped>
Post by Keith Thompson
Post by Richard Heathfield
+++
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory.
Such thing is possible in Windows using the VirtualAlloc() Win32 API
function, if the MEM_RESERVE flag is passed to it.

See its complete description at:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/virtualalloc.asp


Emil


<snipped>
Bill Medland
2006-12-19 01:22:44 UTC
Permalink
Post by Keith Thompson
Post by Richard Heathfield
Post by David T. Ashley
I did not know this was implementation-dependent.
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.
+++
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory. Based on the wording of the standard, I would
expect successive calls to malloc(0) (assuming it doesn't return a
null pointer value) to return distinct values.
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)
--
Bill Medland
Keith Thompson
2006-12-19 01:35:43 UTC
Permalink
Post by Bill Medland
Post by Keith Thompson
Post by Richard Heathfield
Post by David T. Ashley
I did not know this was implementation-dependent.
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.
+++
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.
I wonder how it manages to return a valid pointer without allocating
any actual memory. Based on the wording of the standard, I would
expect successive calls to malloc(0) (assuming it doesn't return a
null pointer value) to return distinct values.
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).
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
CBFalconer
2006-12-19 01:17:35 UTC
Permalink
... snip ...
Post by Keith Thompson
Post by Richard Heathfield
+++
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.
I wonder how it manages to return a valid pointer without
allocating any actual memory. Based on the wording of the
standard, I would expect successive calls to malloc(0) (assuming
it doesn't return a null pointer value) to return distinct values.
Note it doesn't say no memory is consumed, just none is allocated.
I could say the same about nmalloc. As far as the user is
concerned he asked for, and got, zero bytes.
--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
jaysome
2006-12-19 06:01:13 UTC
Permalink
On Mon, 18 Dec 2006 16:29:02 +0000, Richard Heathfield
Post by Richard Heathfield
Post by David T. Ashley
I did not know this was implementation-dependent.
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.
+++
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
--
jay
Serve Laurijssen
2006-12-19 21:22:50 UTC
Permalink
Post by jaysome
On Mon, 18 Dec 2006 16:29:02 +0000, Richard Heathfield
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.
depends if you call access violations graceful ;)
jaysome
2006-12-20 07:36:29 UTC
Permalink
Post by Serve Laurijssen
Post by jaysome
On Mon, 18 Dec 2006 16:29:02 +0000, Richard Heathfield
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.
depends if you call access violations graceful ;)
To me, "graceful" in Windows means no BSOD, just like "graceful" in
*NIX means no kernel panic :^)

Best regards
--
jay
Old Wolf
2006-12-19 21:10:05 UTC
Permalink
Post by Richard Heathfield
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.
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.
Well, the implementation is allowed to return NULL if allocation
failed. So, effectively we have that this implementation may either
return a valid pointer or return NULL in case of malloc(0).

You might say that allocation cannot fail when zero bytes are
requested. However, the standard also says that the pointer
returned should point to the first byte of allocated storage.
So it appears that allocation is required, and therefore, it may fail.
Ben Pfaff
2006-12-18 15:43:51 UTC
Permalink
Post by q***@yahoo.com
Sorry if it might be a stupid question but what should returns
malloc(0) ?
It may return a null pointer or a unique non-null pointer.
--
Peter Seebach on C99:
"[F]or the most part, features were added, not removed. This sounds
great until you try to carry a full-sized printout of the standard
around for a day."
Simon Biber
2006-12-19 01:04:56 UTC
Permalink
Hi,
<HEAD>
What should malloc(0) do? Return a null pointer or a pointer to
0 bytes?
</HEAD>
Welcome to comp.lang.c. Please don't top-post. We prefer inline replying
here. See Posting Styles at Wikipedia:

http://en.wikipedia.org/wiki/Posting_styles

欢迎您来到comp.lang.c。请不要上面回信。那就是在回信时把你写的信全部放在
发信者写的信上面。我们这里较喜欢中间回信,那就是在每一个你想回答的段落下
面写入你的答辩。
--
Simon.
Loading...