Does the following program have undefined behavior?
#include <stdlib.h>
int main (void)
{
void *p = malloc (1);
if (p != NULL) {
free (p);
p;
}
return 0;
}
--
"Mon peu de succès près des femmes est toujours venu de les trop aimer."
--Jean-Jacques Rousseau
> [Now consulting comp.std.c on this.]
>
> Does the following program have undefined behavior?
>
> #include <stdlib.h>
>
> int main (void)
> {
> void *p =3D malloc (1);
> if (p !=3D NULL) {
> free (p);
> p;
> }
> return 0;
> }
No - the above is a syntax error. (Forgot to turn off
quoted-printable, I think, Ben...) :)
To you guys over in c.s.c, it might be worthwhile for you to see the
roots of this post by examining the thread "Malloc help" over here in
c.l.c., especially the followups to Ben's message
<874rt1l...@pfaffben.user.msu.edu>.
Micah
> No - the above is a syntax error. (Forgot to turn off
> quoted-printable, I think, Ben...) :)
Hmm... WTF? I didn't think that this newsreader ever did that.
Let's try again:
#include <stdlib.h>
int main (void)
{
void *p = malloc (1);
if (p != NULL) {
>Does the following program have undefined behavior?
No, I don't think so.
>#include <stdlib.h>
>
>int main (void)
>{
> void *p = malloc (1);
> if (p != NULL) {
>free (p);
>p;
'p' still has a 'valid' value, so evaluating
it should cause no problems. However:
*p;
and out come the 'nasal demons'! :-)
> }
> return 0;
>}
-Mike
(who never dreamed he'd be answering a question
asked by Ben. :-) )
It came through fine for me. It's only in
your message quoting his that I see the
'3D' stuff. Hey cool, everything's in 3D! :-)
-Mike
If the malloc() succeeds, I believe it does.
6.2.4 Storage durations of objects
/6/ [...] The value of a pointer that referred to an object
whose storage is no longer reserved is indeterminate. [...]
... so after the free(), the value of `p' is indeterminate.
3. Terms and Definitions
3.18 undefined behavior
behavior, upon use [...] of indeterminately valued objects [...]
... so undefined behavior occurs if the value of `p' is used after
the free().
The only debatable point I can see is the question of whether the
evaluation of the expression `p' constitutes a "use." I can't find a
formal definition of "use" in the Standard (the N869 draft, actually),
but I find it implausible that an evaluation would not be considered
a "use" under any reasonable definition of the term. The fact that
the value produced is then discarded does not indicate to me that the
evaluation did not occur; it merely suggests a possible optimization.
For my money - open, as always, to correction :)
>#include <stdlib.h>
Legal. :)
>int main (void)
>{
> void *p = malloc (1);
Legal.
> if (p != NULL) {
Legal.
> free (p);
Legal.
> p;
Legal - this is just evaluating a value (as true, presumably).
Since we're not trying to do anything with *p, there's no issue
with using unallocated memory. Therefore no problem.
An interesting variation - is
*p;
legal/defined in this position? At least with that we have to
dereference unallocated memory - but I stioll think it's defined
unless we try to put something in there.
> }
> return 0;
>}
All legal and defined. As far as I can tell.
Cheers,
Dave.
--
.------------------------------.
/ David Neary, \
| E-Mail dne...@eircom.net |
\ Phone +353-1-872-0654 /
`------------------------------'
After the free, p has an indeterminate value, which might be
a trap representation, in which case the behavior would be
undefined (and thus the program would not be strictly
conforming). However, p might have merely an unspecified
value (not a trap representation), in which case the program
is not strictly conforming, but for a different reason.
Somehow C99 forgot to say that the value is indeterminate,
but it is. It could be that that region of address space
was removed from the map by the call to free, in which case
even loading the value into an address register might cause
a trap on some platforms.
In the course of revising the C9x draft, several conformance-
related issues were left in an unsatisfactory state, but the
committee has so far showed little interest in a work item
to address this area.
> Ben Pfaff wrote in message <87zoase...@pfaffben.user.msu.edu>...
> >[Now consulting comp.std.c on this.]
>
> >Does the following program have undefined behavior?
>
> No, I don't think so.
>
> >#include <stdlib.h>
> >
> >int main (void)
> >{
> > void *p = malloc (1);
> > if (p != NULL) {
> >free (p);
> >p;
>
> 'p' still has a 'valid' value, so evaluating
> it should cause no problems.
You're ignoring 6.2.4. Appropriate quote:
6.2.4 Storage durations of objects
...If an object is referred to outside of its lifetime, the
behavior is undefined. The value of a pointer becomes
indeterminate when the object it points to reaches the end of
its lifetime.
Some clc'ers still claim it's defined, though, so I'm looking for
a ruling from comp.std.c.
--
Available for short-term C and Linux contracts through September 2001.
Surely the value of p will be the same as it was before it went
into free? On the other hand, the value of what it points at is
indeterminate.
Regardless of the definition of "use", surely p's value can't be
changed in free...
> On Thu, 28 Jun 2001 17:05:20 -0400, Eric Sosman <Eric....@sun.com> wrote:
> >Ben Pfaff wrote:
> >>
> >> #include <stdlib.h>
> >>
> >> int main (void)
> >> {
> >> void *p = malloc (1);
> >> free (p);
> >> }
> > If the malloc() succeeds, I believe it does.
> >
> > 6.2.4 Storage durations of objects
> >
> >... so after the free(), the value of `p' is indeterminate.
>
> Surely the value of p will be the same as it was before it went
> into free? On the other hand, the value of what it points at is
> indeterminate.
Who says that the value has to change? `indeterminate' include
trap representations. The same pointer value can be valid one
moment, then become a trap representation after the block is
freed.
--
Just another C hacker.
> Ben Pfaff wrote:
> > Does the following program have undefined behavior?
> > free (p);
> > p;
>
> After the free, p has an indeterminate value, which might be
> a trap representation, in which case the behavior would be
> undefined (and thus the program would not be strictly
> conforming). However, p might have merely an unspecified
> value (not a trap representation), in which case the program
> is not strictly conforming, but for a different reason.
>
> Somehow C99 forgot to say that the value is indeterminate,
> but it is.
I think that the quote from 6.2.4 says that the value is
indeterminate well enough:
I agree with you, but just to make it clear even slow-witted people (I'm
not naming any names... yet) get it:
#include <stdlib.h>
int main(void) {
void *p;
if (p=malloc(1)) {
/* AT THIS POINT assume p has the value 0x12345678. For now, ignore
* the fact that an address doesn't have to be a 32-bit value. Now,
* 0x12345678 is a valid address. */
free(p);
/* AT THIS POINT p *still* has the value 0x12345678. *However*,
* 0x12345678 is no longer a valid address, but has changed into a
* trap representation. */
p;
/* This evaluates p, resulting in 0x12345678, which is a trap
* representation, so unspeakable horrors happen. */
}
return 0;
}
The point is, once again, that p DOES NOT get a new value. It is changes
*within* the value, not changes *between* values, which cause the
undefined behaviour.
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"That's no raisin - it's an ALIEN!"
- Tourist in MTV's Oddities
Probably. The library is magic.
>Regardless of the definition of "use", surely p's value can't be
>changed in free...
So? A pointer which is no longer valid at a hardware level can produce
a trap. Imagine a system with an MMU, which checks every pointer when you
load it into an address register...
-s
--
Copyright 2001, all wrongs reversed. Peter Seebach / se...@plethora.net
+--- Need quality network services, server-grade computers, or a shell? ---+
v C/Unix wizard, Pro-commerce radical, Spam fighter. Boycott Spamazon! v
Consulting, computers, web hosting, and shell access: http://www.plethora.net/
> I agree with you, but just to make it clear even slow-witted people (I'm
> not naming any names... yet) get it:
I agree with Pfaff and Gwyn; however, you did not make
anything clear, and was confusing slow-witted people like me.
> p;
> /* This evaluates p, resulting in 0x12345678, which is a trap
> * representation, so unspeakable horrors happen. */
Wait a minute. This is not clear at all:
``expression-statement: expression-opt ;'' (6.8.3p1). So
``p;'' is to be evaluated as an expression statement.
``The expression in an expression statement is evaluated as
a void expression for its side effects'' (6.8.3p2). Therefore
``p'' will be evaluated as a void expression.
``The (nonexistent) value of a void expression (an
expression that has type void) shall not be used in any way, and
implicit or explicit conversions (except to void) shall not be
applied to such an expression. If an expression of any other
type is evaluated as a void expression, its value or designator
is discarded'' (6.3.2.2p1). Since ``p'' belongs to ``any other
type'', it is discarded.
Now, you have to explain why ``discard'' is a kind of
``use'', before jumping to your conclusion...
Tak-Shing
Micah was correct. When I display the original message with
quoted-printable decoding turned off, I see the 3D.
--
Barry Margolin, bar...@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
> On 28 Jun 2001 17:03:48 -0400, Ben Pfaff <pfaf...@msu.edu> wrote:
> >Let's try again:
>
> For my money - open, as always, to correction :)
>
> >#include <stdlib.h>
>
> Legal. :)
>
> >int main (void)
> >{
> > void *p = malloc (1);
>
> Legal.
>
> > if (p != NULL) {
>
> Legal.
>
> > free (p);
>
> Legal.
>
> > p;
>
> Legal - this is just evaluating a value (as true, presumably).
> Since we're not trying to do anything with *p, there's no issue
> with using unallocated memory. Therefore no problem.
That's what I thought.
> An interesting variation - is
> *p;
> legal/defined in this position? At least with that we have to
> dereference unallocated memory - but I stioll think it's defined
> unless we try to put something in there.
What about C99 6.5.3.2#4? I think it's pretty clearly undefined
there.
Micah
--
Computers are basically very fast idiots.
I disagree. This was discussed at length on comp.std.c a while back and the
consensus was that
p;
invoked undefined behavior.
Consider (for example) this post from the thread:
http://groups.google.com/groups?hl=en&safe=off&ic=1&th=1fb91737e927752c,34&see
km=379741F3.CE8239BE%40arl.mil#p
"From: Douglas A. Gwyn (gw...@arl.mil)
Subject: Re: ¶meter
Newsgroups: comp.std.c
Date: 1999/07/22
Norman Diamond wrote:
> This kind of checking could not even be done at translation time.
> In C it is acceptable to take the address of an object, it is useful
> to do various manipulations with pointers, it is valid to assign a
> pointer to another pointer of the same type (unless the destination
> is const), ...
But as Brader pointed out, assignment of an indeterminate value
causes undefined behavior.
A similar, interesting situation is:
p = (char *)malloc(n);
free(p);
if (p != NULL) // undefined ...
*p = 0;
p; // ... because even this is undefined"
> *p;
>
> and out come the 'nasal demons'! :-)
>
> > }
> > return 0;
> >}
>
> -Mike
> (who never dreamed he'd be answering a question
> asked by Ben. :-) )
--
C-FAQ: http://www.eskimo.com/~scs/C-faq/top.html
"The C-FAQ Book" ISBN 0-201-84519-9
C.A.P. FAQ: ftp://cap.connx.com/pub/Chess%20Analysis%20Project%20FAQ.htm
My interpretation:
void *p; /* p's lifetime starts here */
p = maloc(1); /* The void objects lifetime starts here */
free(p); /* The void objects lifetime ends here */
/* p's lifetime has not ended yet */
p; /* What are the effects of this exactly ? */
/* gcc just emits a warning: statement with no effect */
Stef
> Ben Pfaff wrote:
> > Does the following program have undefined behavior?
> > free (p);
> > p;
>
> After the free, p has an indeterminate value, which might be
> a trap representation, in which case the behavior would be
> undefined (and thus the program would not be strictly
> conforming). However, p might have merely an unspecified
> value (not a trap representation), in which case the program
> is not strictly conforming, but for a different reason.
>
> Somehow C99 forgot to say that the value is indeterminate,
> but it is. It could be that that region of address space
> was removed from the map by the call to free, in which case
> even loading the value into an address register might cause
> a trap on some platforms.
C99 does clearly state that the value is indeterminate, but my point
to Ben (which caused this debate to be brought over to you folks at
c.s.c) was that the mere fact that it has an indeterminate value is
insufficient to produce undefined behavior. The only reference to
undefined behavior and trap representations I could find was C99
6.2.6.1#5:
If such a representation is produced by a side effect that modifies
all or any part of the object by an lvalue expression that does not
have character type, the behavior is undefined.
However, in this case, any trap representation contained in p was not
produced by an lvalue expression, nor any kind of expression - it was
caused indirectly by an object's lifetime expiring, so it's not
allowed to be an undefined-behavior-producing trap representation (in
my interpretation, of course).
Micah
--
"Everytime you declare main() as returning void - somewhere a little
baby cries. So please, do it for the children." -- Daniel Fox
> "Mike Wahler" <mkwa...@ix.netcom.com> wrote in message
> news:9hg6gj$73u$1...@slb6.atl.mindspring.net...
> > Ben Pfaff wrote in message <87zoase...@pfaffben.user.msu.edu>...
> > >[Now consulting comp.std.c on this.]
> >
> > >Does the following program have undefined behavior?
> >
> > No, I don't think so.
> >
> > >#include <stdlib.h>
> > >
> > >int main (void)
> > >{
> > > void *p = malloc (1);
> > > if (p != NULL) {
> > >free (p);
> > >p;
> >
> > 'p' still has a 'valid' value, so evaluating
> > it should cause no problems. However:
>
> I disagree. This was discussed at length on comp.std.c a while back and the
> consensus was that
> p;
> invoked undefined behavior.
And this would seem to be my answer (Ben was more or less asking for
my sake, since it had become a debate on c.l.c.).
>
> Consider (for example) this post from the thread:
> http://groups.google.com/groups?hl=en&safe=off&ic=1&th=1fb91737e927752c,34&see
> km=379741F3.CE8239BE%40arl.mil#p
>
> "From: Douglas A. Gwyn (gw...@arl.mil)
> Subject: Re: ¶meter
> Newsgroups: comp.std.c
> Date: 1999/07/22
> Norman Diamond wrote:
> > This kind of checking could not even be done at translation time.
> > In C it is acceptable to take the address of an object, it is useful
> > to do various manipulations with pointers, it is valid to assign a
> > pointer to another pointer of the same type (unless the destination
> > is const), ...
>
> But as Brader pointed out, assignment of an indeterminate value
> causes undefined behavior.
>
> A similar, interesting situation is:
> p = (char *)malloc(n);
> free(p);
> if (p != NULL) // undefined ...
> *p = 0;
> p; // ... because even this is undefined"
Brader's quote of the Standard's definition of 'undefined' in his
message referred to here seems to destroy my argument for it being
defined.
*However*, at the risk of being pedantic, that definition of undefined
is not the same in C99, and I cannot find anything in the new standard
to indicate that use of indeterminately valued objects, by itself, may
produce undefined behavior. There is the fact that indeterminate
values is a superset of trap representations, but as I pointed out
elsethread, this does not fall under the situations where trap
representations may produce undefined behavior (which would probably
rule out trap representations altogether, limiting the set of
indeterminate values for p to be just unspecified).
However, even if the above argument ends up holding water, at this
point it looks to be nothing more than an unintended loophole, so it
looks like I've lost this argument :)
Thanks for your help, all.
Micah
--
"You will be able to move on with your life. You will never
forget what civility and common sense are. They will always be with you,
but you will no longer be in mourning for them."
-- Steve <comm...@vrml3d.com>, on giving in to nitpickery.
The value of a pointer is the position in memory that it points at. The
actual bits that make up 'p' are unchanged, but on some architectures
those bits can cease to represent a valid address, as a result of the
free().
Note that since it's the value which is indeterminate, keeping a copy
elsewhere doesn't help. If you write the bits to a file, then read them
back after the free(), they may represent an invalid value, even though
the value was perfectly valid when they were written.
A pointer's value becomes indeterminate whenever the lifetime of the
object it refers to ends (6.2.4p2). Indeterminate means, among other
things, that it can become a trap value(3.17.2p1). Reading a trap
representation using an lvalue express that does not have character type
(such as 'p;') allows undefined behavior (6.2.6.1p5).
This is not pure theorizing; on many real platforms, executing free()
can cause the freed pointer value to become a trap representation,
without any change to the bit pattern representing that value. This is
because the list of bit patterns that are trap representations of
pointers can change as result of calling free(). On many such platforms,
loading such an illegal pointer value into a register can cause your
program to abort. Because of the cited sections, this is perfect legal
behavior for an implementation of C.
Of course, undefined behavior includes doing absolutely nothing.
Therefore, even on such platforms, an optimizing compiler might drop the
evaluation of 'p;', and you'd be perfectly safe. However, using the
value of 'p' in any more active sense will get you in trouble that even
a super-optimizer can't get you out of, even if you never de-reference
it.
The code invokes undefined behaviour, because p's value is indeterminate
after the call to free().
7.20.3 says: "The value of a pointer that refers to freed space is
indeterminate."
3.18
[#1] undefined behavior
behavior, upon use of a nonportable or erroneous program
construct, of erroneous data, or of indeterminately valued
^^^^^^^^^^^^^^^^^^^^^^
objects, for which this International Standard imposes no
requirements
--
Richard Heathfield : bin...@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Yup, I overlooked that. It seems pretty definitive
to me. What about it do you find ambiguous?
>Some clc'ers still claim it's defined,
>though, so I'm looking for
>a ruling from comp.std.c.
I'd be interested to hear the outcome. You'll
share it here, I hope.
-Mike
(a bit chastened, after having had the audacity
to challenge the great Pfaff. :-) )
The key portion of Ben's quote is:
"...The value of a pointer becomes indeterminate ..."
And we all know that evaluating an object whose
value is indeterminate produces undefined behavior.
Same as:
void foo()
{
int i;
int j = i; // undefined
}
I just didn't realize that the implementation
is no longer required to retain a pointer's value
after it's 'target' 'dies'. The quote makes it
obvious that this is indeed the case. Doesn't
make a whole lot of sense to me, but hey, those
guys at ISO are certainly more knowledgable than I. :-)
>/* gcc just emits a warning: statement with no effect */
Standard response: An implementation does not define
the language!
-Mike
Yes, the part I overlooked was that a
pointer's value is indeterminate after
its target 'dies'.
I spoke too soon, out of ignorance.
My apologies.
-Mike
> Yup, I overlooked that. It seems pretty definitive
> to me. What about it do you find ambiguous?
It's not me, it's some others around clc.
> >Some clc'ers still claim it's defined,
> >though, so I'm looking for
> >a ruling from comp.std.c.
>
> I'd be interested to hear the outcome. You'll
> share it here, I hope.
This thread is crossposted so just keep reading.
> -Mike
> (a bit chastened, after having had the audacity
> to challenge the great Pfaff. :-) )
Heh.
--
"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
> Dave Neary wrote:
> >
> > On 28 Jun 2001 17:03:48 -0400, Ben Pfaff <pfaf...@msu.edu> wrote:
> ...
> > > free (p);
> >
> > Legal.
> >
> > > p;
> >
> > Legal - this is just evaluating a value (as true, presumably).
> > Since we're not trying to do anything with *p, there's no issue
> > with using unallocated memory. Therefore no problem.
>
> A pointer's value becomes indeterminate whenever the lifetime of the
> object it refers to ends (6.2.4p2). Indeterminate means, among other
> things, that it can become a trap value(3.17.2p1). Reading a trap
> representation using an lvalue express that does not have character type
> (such as 'p;') allows undefined behavior (6.2.6.1p5).
Actually, that section applies to /producing/ a trap representation,
not reading, AFAICT.
"Certain object representations need not represent a value of the object
type. If the stored value of an object has such a representation and is
read by an lvalue expression that does not have character type, the
behavior is undefined. If such a representation is produced by a side
effect that modifies all or any part of the object by an lvalue
expression that does not have character type, the behavior is
undefined.41) Such a representation is called a trap representation."
The first sentence describes trap representations; the second says that
reading one in certain ways allows undefined behavior, the third says
that creating one in certain ways allows undefined behavior, and the
fourth sentence officially names such representations. My statement was
almost a verbatim quote of the second sentence, and it applies to this
case.
The second and third sentences are not redundant; it's possible to
create such a value in ways (such as calling free()) that don't cause
the third sentence to apply. It's possible to read such representations
in ways (such as memcpy()) such that the second sentence doesn't apply.
Keep in mind that the value of a pointer is very different from it's bit
pattern. For instance, the bit pattern could contain a segment number
and an offset within that segment; after free(), the segment might be
released, rendering all pointers using that segment number meaningless.
The value of a pointer is the location in memory that it points at, and
if it no longer points at any real memory, the value has changed, even
if the bit pattern is unchanged.
> "Certain object representations need not represent a value of the object
> type. If the stored value of an object has such a representation and is
> read by an lvalue expression that does not have character type, the
> behavior is undefined. If such a representation is produced by a side
> effect that modifies all or any part of the object by an lvalue
> expression that does not have character type, the behavior is
> undefined.41) Such a representation is called a trap representation."
>
> The first sentence describes trap representations; the second says that
> reading one in certain ways allows undefined behavior, the third says
> that creating one in certain ways allows undefined behavior, and the
> fourth sentence officially names such representations. My statement was
> almost a verbatim quote of the second sentence, and it applies to this
> case.
Geez. I've read that particular paragraph about 6 times today due to
this discussion, and would've saved myself some grief if I'd just read
it *once* carefully. Looks like I'll be joining Mr. Heathfield's
"Reading for Comprehension 101".
I'm afraid I still don't understand... I understand that p is not
a valid pointer, and that it's value (as a void *) is
indeterminate - but I don't get why evaluating it like this is
necessarily a use of the address - surely the return value is
automatically discarded, which isn't a use of the value?
Another interesting value - assuming that long long int can hold
all the possible values of a void * (I'm not sure if this is
guaranteed by the standard), is
(long long int)p;
defined?
Cheers,
Dave.
--
David Neary, E-Mail dave.dot.neary.at.palamon.dot.ie
Palamon Technologies Ltd. Phone +353-1-634-5059
>James Kuyper Jr. wrote:
>> The value of a pointer is the position in memory that it points at. The
>> actual bits that make up 'p' are unchanged, but on some architectures
>> those bits can cease to represent a valid address, as a result of the
>> free().
>
>I'm afraid I still don't understand... I understand that p is not
>a valid pointer, and that it's value (as a void *) is
>indeterminate - but I don't get why evaluating it like this is
>necessarily a use of the address - surely the return value is
>automatically discarded, which isn't a use of the value?
on some machines addresses are loaded into special registers and at that
time the address is validated before any subsequent instruction that would
use the address
an optimizer or peepholer would discard the 'p;' statement as dead but
unoptimized code might keep it
It can't be. The first sentence of 6.3.2.2p1 that you quoted mentions that
the value "shall not be used", so discarding is obviously not a "use" of the
value.
#include <stdlib.h>
int main (void)
{
void *p = malloc (1);
if (p != NULL) {
free (p);
p;
}
return 0;
}
> Some clc'ers still claim it's defined, though, so I'm looking for
> a ruling from comp.std.c.
It is basically the same problem as in
p = malloc (...);
q = realloc (p, ...);
if (p == q) { ... }
I would say it is undefined. Unlikely to cause any problem in a real
implementation. On the other hand, if I created a debugging C compiler
that tries to detect any kinds of errors in your program, and your
compiled program would complain at runtime:
"Error: Using deallocated pointer. "
I don't think you could complain that this compiler is not conforming.
Think about a standard PC twelve years ago. It is a 80286. It has a
so-called "protected mode" where it can adress up to 16 MBytes of ram.
Each access uses two 16-bit registers, a "segment" and an "offset".
The segment is actually a pointer to a table which tells where the
segment begins and where is ends, and what access rights are granted
to that segment.
The verification of acces rights is done when the segment register is
loaded; so you do not even need to dereference a pointer to be killed by
unauthorized access to some memory: merely putting the value where it
deserves (a segment value in a segment register) triggers the bazooka.
This situation is real: I believe the given program could truly have
crashed with OS/2 or Windows 3.0 in "standard mode" on a 286.
--Thomas Pornin
The "shall not be used" applies only to the "nonexistant value of a void
expression". When a non-void expression is evaluated as a void
expression, it does have a value, and evaluation of that value is
carried out far enough to trigger any relevant side-effects, before the
value is discarded. If the object has a trap representation, and if the
undefined behavior allowed by reading that trap representation includes
any observable behavior, then that counts as a side-effect.
Keep in mind that you don't need 3.18, which talks about using
indeterminate values, to show that this allows undefined behavior.
Section 6.2.6.1p5, second sentence, allows undefined behavior just
because the value is read, whether or not it's used.
Systems that validate the values loaded into address registers are quite
real, and it's quite possible for deallocation to render a particular
address pointing into deallocated memory invalid. Until you know for
certain that the memory pointed at by p was not deallocated, you can't
safely use the value of 'p'. That's the case only when 'q' is a null
pointer.
LOAD_ADDR P ; traps if P is not mapped
You missed the preceding sentence in the same paragraph,
which is the relevant specification here. In "p;" the "p" is
an lvalue expression that does not have character type and is
used to read the value of the object associated with the
identifier "p". Therefore if the "value" is really a trap
representation, the behavior is undefined. It is not the
existence of the trap representation sitting quietly in the
object that is the problem, it's the activation of that trap
representation by trying to use it as the value of the object.
(If the value is not a trap representation, then it is merely
unspecified, in which case the example is not strictly
conforming due to use of an unspecified value.)
The discard happens after the use. Actually it is merely
"reading" the trap representation that constitutes undefined
behavior.
The standard does not guarantee it.
That depends on the malloc implementation, a e.g a malloc that
uses mmap you are in trouble.
Dave Neary wrote:
... free(p); ...
>
> Regardless of the definition of "use", surely p's value can't be
> changed in free...
Isn't it possible that it could be, if free() were
a macro? It doesn't have to follow the usual
function rules.
Dennis
>> (Forgot to turn off quoted-printable, I think, Ben...) :)
>
> Hmm... WTF? I didn't think that this newsreader ever did that.
The first one looked fine (quoted-printable-wise) here. Problem
maybe occurred inbetwixt?
--
|_ CJSonnack <Ch...@Sonnack.com> _____________| How's my programming? |
|_ http://www.Sonnack.com/ ___________________| Call: 1-800-DEV-NULL |
|_____________________________________________|_______________________|
Opinions expressed herein are my own and may not represent those of my employer.
> Micah was correct. When I display the original message with
> quoted-printable decoding turned off, I see the 3D.
Yep. I was wrong. I didn't even realize Netscape's newsreader could
do that, so I lernt sumthin!
> Ben Pfaff wrote:
>
> >> (Forgot to turn off quoted-printable, I think, Ben...) :)
> >
> > Hmm... WTF? I didn't think that this newsreader ever did that.
>
> The first one looked fine (quoted-printable-wise) here. Problem
> maybe occurred inbetwixt?
No, it was an actual newsreader issue. Gnus has so many knobs
that you can twist and hooks you can set up, and I hadn't hooked
something in the way I'd intended. Now I have it set up to
consider Usenet an 8-bit medium.
--
"In My Egotistical Opinion, most people's C programs should be indented six
feet downward and covered with dirt." -- Blair P. Houghton
But what about (error checking omitted for brevity):
int *p1, *p2;
p1 = malloc(sizeof int);
p2 = p1;
free(p1);
p2;
I defy a macro implementation of free() to change the value of p2.
Actually, I suppose it's conceivable that an implementation could maintain
an inverted index of all pointers, so when an object is freed it can find
all the pointer variables that point to it and zap them. But if you
replace 'p2 = p1;' with:
my_memcpy(&p2, &p1, sizeof p1);
where my_memcpy() is a user-written function that performs byte-by-byte
copying (I'm avoiding using memcpy(), since this built-in function could
participate in the magic).
My point is that whatever mechanism you use to get p1's value into p2, they
both share the same validity. Evaluating p2 after the free() is undefined
if and only if evaluating p1 is undefined.
--
Barry Margolin, bar...@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
Barry Margolin wrote:
> >Isn't it possible that it could be, if free() were
> >a macro? It doesn't have to follow the usual
> >function rules.
>
> But what about (error checking omitted for brevity):
>
> int *p1, *p2;
>
> p1 = malloc(sizeof int);
> p2 = p1;
> free(p1);
> p2;
>
> I defy a macro implementation of free() to change the value of p2.
I'll give you that. But changing p1 should be possible
(and it might even be a service to make it null or
a trap representation). You wouldn't legally be able
to tell.
[sorry for the shortened posts just before]
Dennis
What about this, then:
const int *foo = malloc(sizeof *foo);
free(foo);
or this:
int *bar = malloc(sizeof *bar);
free((void *) bar);
A free macro using standard C operators would fail on these if it
tried to modify its argument. I'd expect a solution using compiler
magic to be considerably easier to implement than preprocessing
hacks that work in all cases.
Gergo
--
"It's what you learn after you know it all that counts."
-- John Wooden
Regarding
char* p = malloc (SIZE);
free (p);
p;
the Standard (final draft) says quite clearly that (assuming malloc
succeeds) the value of p becomes indeterminate after the call to free
(6.2.4#6 and 7.20.3#1).
Some people seem to be saying that the implementation can actually change
the value/bit pattern of p as a result of free doing whatever it does:
Micah Cowan:
> It's not that free() is changing the value -
> the implementation itself has license to do
> so when the object's lifetime expires.
I had a hard time accepting this one, and I babbled about pass-by-value for
a while, but the Standard does say explicitly that the value becomes
indeterminate, so I suppose Micah is right here.
Other people are saying that even if the implementation is NOT changing the
value/bit pattern of p, the behavior is still undefined because the value is
indeterminate.
Ben Pfaff:
> Whether it changes, or not, doesn't matter. Either
> way, the value of `p', along with all other pointers
> into the same freed block, become indeterminate.
This doesn't make sense. Indeterminate means that the value can have
changed to whatever it wants. If it doesn't change, it can't become
indeterminate.
So, having agreed that p's value can change and hence become indeterminate,
let's address the question of whether an expression involving an
indeterminate value produces undefined behavior.
Some people are even saying that
int i;
i;
produces undefined behavior. Wow... I don't think so. i is indeterminate,
yes. But we're discarding the result. All possible values for i produce
the same effect.
Now everyone is going to bite my head off with 3.18#1, which defines
undefined behavior as "behavior, upon use of a nonportable or erroneous
program construct, of erroneous data, or of indeterminately valued objects,
for which this International Standard imposes no requirements".
If you read this very carefully, I think you will see that it does *not*
imply that
the use of indeterminately valued objects yields undefined behavior.
Instead it defines undefined behavior as bevhaior *whose outcome is not
regulated by the Standard*, which happens to arise due to indeterminately
valued objects etc. Everything after the word "objects" is a restrictive
subordinate clause, indicating that the Standard must specify elsewhere the
cases in which it is choosing not to impose requirements.
Notice that if the Standard really had meant to define undefined behavior as
any behavior resulting from the use of indeterminately valued objects, then
int i;
sizeof i; /* i IS an indeterminately valued object */
would be undefined. Now everyone is going to tell me that sizeof does not
access the value of its operand. True, but "use" is not explicitly defined,
and I see no reason to think that 'sizeof i;' *uses* i any less than 'i;'
does, just because one converts i into an rvalue and the other doesn't.
All this applies equally well to freed pointers. After
int p;
p;
p is just as indeterminately valued as it is after
char* p = malloc (SIZE);
free (p);
I hope I don't need to remind anyone that we are not dereferencing the
pointer. That would produce undefined behavior in accordance with 6.5.3.2#4
(and probably elsewhere, since that section is specific to the * operator).
Discussions of segment registers are largely irrelevant. This is about what
the Standard stipulates, and it would seem that an implementation must not
crash or invoke demons when it encounters
p;
If that means not loading p into hardware registers that fault upon
receiving invalid pointers, then that's exactly what the implementation must
not do.
I believe I've addressed all the arguments... Please tell me why I'm wrong,
as I'm sure many of you think I am.
> Dennis Ritchie <d...@bell-labs.com> wrote:
> > I'll give you that. But changing p1 should be possible
> > (and it might even be a service to make it null or
> > a trap representation). You wouldn't legally be able
> > to tell.
>
> What about this, then:
> const int *foo = malloc(sizeof *foo);
> free(foo);
>
> or this:
> int *bar = malloc(sizeof *bar);
> free((void *) bar);
>
> A free macro using standard C operators would fail on these if it
> tried to modify its argument. I'd expect a solution using compiler
> magic to be considerably easier to implement than preprocessing
> hacks that work in all cases.
>
> Gergo
I don't think that matters, though. The Standard specifically says
that the value of a pointer to an object whose lifetime has expired
"becomes indeterminate". It doesn't have to follow normal semantic
procedures of macros /or/ functions in order to do that. It has
nothing to do with the free() function (or macro) itself, as far as
the Standard is concerned. Seems to me an implementation is free to
keep track of what pointers point to an object (just as
garbage-collecting language implementations do), and set all those
pointers to a new value, just because.
Also, bear in mind that in terms of implementation, free() doesn't
have to be either a macro /or/ even a "real" function - it can be
built-in to the implementation itself (recall that standard headers
don't have to correspond to real files). Such an implementation could
do whatever it wants to an argument to free() in that instance, since
it falls squarely within the assertation of the Standard that that
argument's value becomes indeterminate.
Example:
#include <stdlib.h>
#include <string.h>
int main (void)
{
char *foo, *bar, *baz;
foo = malloc (80);
bar = baz = foo;
strcpy (foo, "Hello");
/* At this point, bar, baz and foo all have values that are squarely
"determinate". They all point to an object 80 bytes in size,
which contains the string "Hello". */
free (foo);
/* At this point, as far as the Standard is concerned, the above
free() can have not only set foo to NULL (or a trap representation
or anything that falls under "indeterminate value", which is, uh,
anything), but can have automagically have set the values of bar and
baz to NULL (or whatever) as well. This satisfies all demands
of the Standard, AFAICT. */
return 0;
}
--
"You will be able to move on with your life. You will never
forget what civility and common sense are. They will always be with you,
but you will no longer be in mourning for them."
-- Steve <comm...@vrml3d.com>, on giving in to nitpickery.
>Much of this was also posted in the c.l.c "Malloc help" thread. In this
>thread, everyone basically said the same stuff we said over there anyways.
>I'm going to try to summarize my position on everything.
<snip>
>Other people are saying that even if the implementation is NOT changing the
>value/bit pattern of p, the behavior is still undefined because the value is
>indeterminate.
>
>Ben Pfaff:
>> Whether it changes, or not, doesn't matter. Either
>> way, the value of `p', along with all other pointers
>> into the same freed block, become indeterminate.
>
>This doesn't make sense. Indeterminate means that the value can have
>changed to whatever it wants.
No, it means you can't determine it. It may have remained quite the
same. You cannot tell.
>If it doesn't change, it can't become indeterminate.
Non sequitur.
This is a physics problem. Lets say i put a chair in a room. You can
see that there's one chair. Now I turn out the light, and give you an
atom bomb. Thats the only tool you have to measure where the chair is.
Can you do it ? No. Its position and even its presence is
indeterminate because the act of trying to measure it will destroy the
evidence..
>So, having agreed that p's value can change and hence become indeterminate,
>let's address the question of whether an expression involving an
>indeterminate value produces undefined behavior.
>
>Some people are even saying that
> int i;
> i;
>produces undefined behavior. Wow... I don't think so. i is indeterminate,
>yes. But we're discarding the result.
but first we're evaluating i.
> All possible values for i produce the same effect.
>
>Now everyone is going to bite my head off with 3.18#1, which defines
>undefined behavior as "behavior, upon use of a nonportable or erroneous
>program construct, of erroneous data, or of indeterminately valued objects,
>for which this International Standard imposes no requirements".
>
>If you read this very carefully, I think you will see that it does *not*
>imply that
>the use of indeterminately valued objects yields undefined behavior.
I read it. It does.
>Instead it defines undefined behavior as bevhaior *whose outcome is not
>regulated by the Standard*, which happens to arise due to indeterminately
>valued objects etc.
Correct. And we've agreed that p is one so....
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
The implementation will almost certainly not change the bit pattern, but
it can change the value - without changing the bit pattern.
> Ben Pfaff:
> > Whether it changes, or not, doesn't matter. Either
> > way, the value of `p', along with all other pointers
> > into the same freed block, become indeterminate.
>
> This doesn't make sense. Indeterminate means that the value can have
> changed to whatever it wants. If it doesn't change, it can't become
> indeterminate.
Yes it can. Every implementation creates a map (in the mathematical
sense of the term) between bit patterns and memory locations. For some
platforms this map is simple and constant: the bit pattern directly
encodes a hardware memory address. On other platforms, the map is more
complicated, and can change from time to time. A conforming
implementation of C has to implement pointers in a way that survives
these changes under ordinary circumstances. However, the standard
explicitly allows free() to render a pointer's value indeterminate, and
that was done precisely in order to allow implementation of C on such
platforms. That clause means that free() can change the connection
between bit patterns and memory locations, at least with respect to
pointers that used to point into the deallocated memory.
The net result is that, with no change to the bit pattern, the pattern
might no longer represent a valid memory location. The value of the
pointer is indeterminate, even though it contains the same bit pattern
that, before the call to free(), represented a well-determined value.
Specifically, this invalid pointer representation can now be a trap
representation. This is true not only of that pointer, but of every
other pointer into the same block of deallocated memory, regardless of
the pointer type, and regardless of whether or not the pointer is stored
anywhere that's accessible to the implementation. You could print out
the bit pattern of the pointer, have it stored in the user's head, have
him write that pattern back after the free(), and it will now represent
an invalid pointer value.
> So, having agreed that p's value can change and hence become indeterminate,
> let's address the question of whether an expression involving an
> indeterminate value produces undefined behavior.
With some fancy compiler magic, 'p's value might change, but that can't
be the explanation why ALL pointers into the deallocated memory can have
their value become indeterminate. Those pointers could be scattered all
throughout the program (and even outside of it, as described above). The
reason they become indeterminate has nothing to do with the
representation of the pointer - it has everything to do with changes to
the map connecting the representation of the pointer, and the value it
represents.
> char* p = malloc (SIZE);
> free (p);
...
> Discussions of segment registers are largely irrelevant. This is about what
You're right. The segment registers concept merely explains why the
standard allows undefined behavior in this case. The key fact is that
the standard does specify that this code allows undefined behavior; why
it does so is only of historical and didactic interest. Well, it's also
of importance to have a model in you head, showing HOW the nasty
behaviour could occur. Without the model, it can be hard to understand
what the rule means. However, it's the rule that matters, not the model.
> the Standard stipulates, and it would seem that an implementation must not
> crash or invoke demons when it encounters
> p;
The standard states that the value of p is indeterminate, and that
indeterminate values can include trap representations. It further
specifies that reading the value of an trap representation allows
undefined behavior (direct citations from the standard and more precise
wording may be found elsewhere on this thread). You've said nothing to
address that line of argument.
> If that means not loading p into hardware registers that fault upon
> receiving invalid pointers, then that's exactly what the implementation must
> not do.
Why not?
If you can't tell whether it's the same, that's the same as saying it may
have changed. If you knew it couldn't change, you would know that it was
the same.
> This is a physics problem. Lets say i put a chair in a room. You can
> see that there's one chair. Now I turn out the light, and give you an
> atom bomb. Thats the only tool you have to measure where the chair is.
> Can you do it ? No. Its position and even its presence is
> indeterminate because the act of trying to measure it will destroy the
> evidence..
You saw the chair while the light was on. Either the chair can move or it
can't. If it can move, then yes, its position is indeterminate. If it
can't move, then you know where it is and you don't need to use the atom
bomb.
> but first we're evaluating i.
which does not necessarily produce undefined behavior.
> >If you read this very carefully, I think you will see that it does *not*
> >imply that
> >the use of indeterminately valued objects yields undefined behavior.
>
> I read it. It does.
No, it doesn't. At first it seems to say
"Undefined behavior is any behavior resulting from using indeterminately
valued objects, or blah blah blah, etc., and, incidentally, the standard
imposes no requirement for it."
But in actuality, its meaning is
"Undefined behavior is any behavior for which the standard imposes no
requirement, and, incidentally, whenever it occurs, it is the result of
using indeterminately valued objects, or blah blah blah, etc."
As even further clarification, here's something I also posted in the Malloc
Help thread:
Suppose I define death like this:
DEATH
an event, upon contracting a disease, falling from a building, or angering a
C programmer beyond endurance, in which one's body ceases to have life.
It seems to me that this is an okay definition of death (aside from the fact
that there are other ways of dying besides those mentioned).
It does not follow from this definition that if you contract a disease, you
will die. Many people contract diseases and recover quickly. Many people
fall from buildings and experience only a few broken bones.
Similarly, the standard defines
UNDEFINED BEHAVIOR
behavior, upon use of indeterminately valued objects, blah blah blah, for
which the Standard imposes no requirement
Same sentence structure, same idea. It does not say that this behavior
*must occur* upon use of indeterminately valued objects.
>> No, it means you can't determine it. It may have remained quite the
>> same. You cannot tell.
>
>If you can't tell whether it's the same, that's the same as saying it may
>have changed.
Yes, thats what I said. And ?
>If you knew it couldn't change, you would know that it was
>the same.
Sure, but all you know is you don't know. Are you clinically stupid?
>> This is a physics problem. Lets say i put a chair in a room. You can
>> see that there's one chair. Now I turn out the light, and give you an
>> atom bomb. Thats the only tool you have to measure where the chair is.
>> Can you do it ? No. Its position and even its presence is
>> indeterminate because the act of trying to measure it will destroy the
>> evidence..
>
>You saw the chair while the light was on. Either the chair can move or it
>can't.
You have no clue at all do you.
The light goes out, and an invisible space ship teleports it to mars.
Can you tell that ?
>If it can move, then yes, its position is indeterminate. If it
>can't move, then you know where it is and you don't need to use the atom
>bomb.
Thanks for that. And the relevance is ?
>> but first we're evaluating i.
>
>which does not necessarily produce undefined behavior.
Yes it does.
>> >If you read this very carefully, I think you will see that it does *not*
>> >imply that
>> >the use of indeterminately valued objects yields undefined behavior.
>>
>> I read it. It does.
>
>No, it doesn't. At first it seems to say
for cripes sakes stop this. You're wrong you idiot. Cut your losses
before everyone killfiles you.
> On Fri, 29 Jun 2001 16:19:17 -0700, "Steven Kobes"
> <ko...@u.arizona.edu> wrote:
>
> >Ben Pfaff:
> >> Whether it changes, or not, doesn't matter. Either
> >> way, the value of `p', along with all other pointers
> >> into the same freed block, become indeterminate.
> >
> >This doesn't make sense. Indeterminate means that the value can have
> >changed to whatever it wants.
>
> No, it means you can't determine it. It may have remained quite the
> same. You cannot tell.
No - it means (*ahem*):
either an unspecified value or a trap representation
(official quote)
Among other things, this means that all unspecified values are also
indeterminate, yet you can determine them (anyone for updating this
definition, then? Seems contradictory... :) )
> >If it doesn't change, it can't become indeterminate.
>
> Non sequitur.
Agreed (though by saying this I am contradicting a statement made a
couple days ago). In practice, my assertion that an implementation
may literally change values on you, while supported by the Standard,
is extremely unlikely. As others have pointed out, it is more likely
that a previously valid value becomes a trap representation, which is
a type of indeterminate value.
Micah
--
Computers are basically very fast idiots.
But the argument to free() isn't necessarily an lvalue.
If there's a macro implementation of free() that modifies its argument
and doesn't break the following legal program, I'll be very surprised:
========================================================================
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
int main(void)
{
char *ptr = malloc(100);
char *ptr_plus_5;
if (ptr == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
ptr_plus_5 = ptr + 5;
free(ptr_plus_5 - 5);
printf("No nasal demons so far...\n");
exit(EXIT_SUCCESS);
} /* main */
========================================================================
Actually I can imagine such an implementation, but it would require
compiler magic to determine whether it can modify its arguments --
perhaps something like
#define free(x) __MAGIC_FREE(x)
Either that, or it could invoke a scavenging routine that modifies all
pointer variables that have the same value as the argument. In this
case, it would modify the value of ptr.
There was a debate some time ago about whether the raw value of a
pointer variable, accessed as an array of unsigned char, can legally
be changed by a call to free(). I believe the debate itself triggered
nasal demons, regardless of the behavior of any actual code being
discussed.
--
Keith Thompson (The_Other_Keith) k...@cts.com <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://www.sdsc.edu/~kst>
Cxiuj via bazo apartenas ni.
You are being unnecessarily belligerent, and you don't seem to be taking the
time to examine my points at all. I don't understand why anyone would
killfire someone for respectfully expressing his views in a discussion that
is relevant to the newsgroup. Please, exercise a little more maturity the
next time you participate in a debate.
Right. Because the same bit pattern may no longer be a "safe" value...
Imagine that you say "this can't fall, I put it down where the table was
twenty minutes ago". ;)
>This doesn't make sense. Indeterminate means that the value can have
>changed to whatever it wants. If it doesn't change, it can't become
>indeterminate.
Sure it can, if it's a pointer, because the determinacy of a pointer may
vary.
>Some people are even saying that
> int i;
> i;
>produces undefined behavior. Wow... I don't think so. i is indeterminate,
>yes. But we're discarding the result. All possible values for i produce
>the same effect.
No. At least one possible value might produce "segmentation fault; core
dumped".
>Now everyone is going to bite my head off with 3.18#1, which defines
>undefined behavior as "behavior, upon use of a nonportable or erroneous
>program construct, of erroneous data, or of indeterminately valued objects,
>for which this International Standard imposes no requirements".
The intent was, indeed, to say that indeterminately valued objects produced
undefined behavior, but this got cleaned up with the trap representation
stuff in C99.
>If you read this very carefully, I think you will see that it does *not*
>imply that the use of indeterminately valued objects yields undefined
>behavior.
I always thought it did. :)
>Instead it defines undefined behavior as bevhaior *whose outcome is not
>regulated by the Standard*, which happens to arise due to indeterminately
>valued objects etc.
No, it says that (behavior whose outcome is not regulated by the standard)
arises as a result of (circumstances, one of which is the use of
indeterminately valued objects).
>Notice that if the Standard really had meant to define undefined behavior as
>any behavior resulting from the use of indeterminately valued objects, then
> int i;
> sizeof i; /* i IS an indeterminately valued object */
>would be undefined. Now everyone is going to tell me that sizeof does not
>access the value of its operand. True, but "use" is not explicitly defined,
>and I see no reason to think that 'sizeof i;' *uses* i any less than 'i;'
>does, just because one converts i into an rvalue and the other doesn't.
Evaluation is use.
>All this applies equally well to freed pointers. After
> int p;
> p;
>p is just as indeterminately valued as it is after
> char* p = malloc (SIZE);
> free (p);
Yup.
>I believe I've addressed all the arguments... Please tell me why I'm wrong,
>as I'm sure many of you think I am.
Trap representations. Once a pointer is invalid, it is allowed to be a
magic cookie which smells like a pointer, but which immediately crashes
on any evaluation.
p;
evaluates "p" ("for its side effects") and discards the value... but it
*does* produce a value, before discarding it.
-s
--
Copyright 2001, all wrongs reversed. Peter Seebach / se...@plethora.net
+--- Need quality network services, server-grade computers, or a shell? ---+
v C/Unix wizard, Pro-commerce radical, Spam fighter. Boycott Spamazon! v
Consulting, computers, web hosting, and shell access: http://www.plethora.net/
The ability to say "there is no way visible to me that this could have
changed" doesn't mean "I can investigate this and confirm this belief".
>> but first we're evaluating i.
>which does not necessarily produce undefined behavior.
Yes, it does, because of trap representations.
>"Undefined behavior is any behavior resulting from using indeterminately
>valued objects, or blah blah blah, etc., and, incidentally, the standard
>imposes no requirement for it."
>But in actuality, its meaning is
>"Undefined behavior is any behavior for which the standard imposes no
>requirement, and, incidentally, whenever it occurs, it is the result of
>using indeterminately valued objects, or blah blah blah, etc."
No, it isn't. If you feel otherwise, you're certainly welcome to come to
a future meeting and convince the committee. ;)
>Same sentence structure, same idea. It does not say that this behavior
>*must occur* upon use of indeterminately valued objects.
Sure it does. It just happens to say it in an arguably unclear way - thus
trap representations, which say what you need.
Even if it's not a macro. For all we know, the implementation secretly
passes the addresses of arguments (or null pointers, when arguments are
expressions) into free, or keeps lists of pointers... It's Allowed.
Someone once reported some implementation where:
free(p);
on a valid pointer resulted in a "p" which compared equal to 0. I am
not sure I believe in this, but I think it's about as likely as "domesticated"
cats, and I believe in those.
Every copy of the pointer value is considered indeterminate, not just the one
stored in p.
Also, p could be a const-qualified object.
Note also that, even if free() is defined as a macro, it also has to
be implemented as a function. For example:
(free)(x);
has to call the actual function.
Such a function could still be magical, but having an actual function
modify its argument gets closer to the edge of legitimacy.
Or I suppose the macro and the function could behave differently, as
long as no strictly conforming program can tell the difference.
>> You're wrong you idiot. Cut your losses
>> before everyone killfiles you.
>
>You are being unnecessarily belligerent, and you don't seem to be taking the
>time to examine my points at all.
Your points have been debated to death over many days. You don't seem
to get it. You're considered to be wrong by practically the entire C
community, including many on the ISO committee.
>I don't understand why anyone would
>killfire someone for respectfully expressing his views in a discussion that
>is relevant to the newsgroup.
Because you refuse to listen, ignore reasoned discussion etc. In CLC
people are generally killfiled for being pains in teh butt.
>Please, exercise a little more maturity the
>next time you participate in a debate.
Don't be such a pompous arass.
>Mark McIntyre <ma...@garthorn.demon.co.uk> writes:
>
>> On Fri, 29 Jun 2001 16:19:17 -0700, "Steven Kobes"
>> <ko...@u.arizona.edu> wrote:
>>
>> >Ben Pfaff:
>> >> Whether it changes, or not, doesn't matter. Either
>> >> way, the value of `p', along with all other pointers
>> >> into the same freed block, become indeterminate.
>> >
>> >This doesn't make sense. Indeterminate means that the value can have
>> >changed to whatever it wants.
>>
>> No, it means you can't determine it. It may have remained quite the
>> same. You cannot tell.
>
>No - it means (*ahem*):
>
> either an unspecified value or a trap representation
>
>(official quote)
you're right.
>Among other things, this means that all unspecified values are also
>indeterminate, yet you can determine them
The problem is, you can't determine them without invoking UB....
>(anyone for updating this
>definition, then? Seems contradictory... :) )
Or hard to read.... :->
>> >If it doesn't change, it can't become indeterminate.
>>
>> Non sequitur.
>
>Agreed (though by saying this I am contradicting a statement made a
>couple days ago). In practice, my assertion that an implementation
>may literally change values on you, while supported by the Standard,
>is extremely unlikely. As others have pointed out, it is more likely
>that a previously valid value becomes a trap representation, which is
>a type of indeterminate value.
>
>Micah
--
>> You're wrong you idiot. Cut your losses
>> before everyone killfiles you.
>
>You are being unnecessarily belligerent,
Uh, this was belligerent ? You've not been out much have you?
You can determine their object representation by inspecting the object's
bytes via unsigned char lvalues. While this is not exactly the same as
determining the value, it comes pretty close; and in particular you can
can determine when the object's bits do change.
-- Niklas Matthies
>On Sat, 30 Jun 2001 23:56:37 +0100, Mark McIntyre <ma...@garthorn.demon.co.uk> wrote:
>> On 29 Jun 2001 17:59:01 -0700, Micah Cowan <mi...@cowanbox.com> wrote:
>[毽愍
>> >Among other things, this means that all unspecified values are also
>> >indeterminate, yet you can determine them
>>
>> The problem is, you can't determine them without invoking UB....
>
>You can determine their object representation by inspecting the object's
>bytes via unsigned char lvalues.
This is true, but in that case you're not examining the object itself.
>While this is not exactly the same as
>determining the value, it comes pretty close; and in particular you can
>can determine when the object's bits do change.
However I suspect since you can by this method examine trap
representations, it de facto is not properly examining the object.
I don't think that the fact of the value of some object becoming
indeterminate allows the implementation to change the object
representation. At least that's not the intent of the standard, although
I couldn't find any wording that actually forbids it. Anyway, this is
not specific to objects with an indeterminate value; objects with a
defined value could change their representation as well (as long as the
value isn't changed by this). For example, in
int i = 5;
const unsigned char * const p = (const unsigned char *) &i;
unsigned char x[sizeof(int)];
int r = 0;
size_t n;
for (n = 0; n < sizeof(int); n++) x[n] = p[n];
for (n = 0; n < sizeof(int); n++) if (x[n] != p[n]) { r = 1; break; }
the standard doesn't seem to actually forbid that r becomes 1 (if there
is more than one int object representation for 5); but it is very likely
the intent that it isn't allowed to.
-- Niklas Matthies
Of course you do. An object is a contiguous sequence of bytes the
contents of which can represent values. when you talk about "the value
of an object", you actually mean "the value represented by the bit
pattern stored into the bytes of an object via an lvalue of some
specific type" or "the value represented by the bit pattern contained in
the bytes of an object when accessing it by an lvalue of some specific
type". An object per se has no type, it only is related to a type with
respect to a specific access to the object.
-- Niklas Matthies
Of course you do. An object is a contiguous sequence of bytes the
contents of which can represent values. When you talk about "the value
[snip]
If you modified that to a definition of DEADLY BEHAVIOUR then it
would be a more accurate analogy and you would see that it was
possibly that death *may occur* from any of those behaviours.
>Similarly, the standard defines
>
> UNDEFINED BEHAVIOR
>behavior, upon use of indeterminately valued objects, blah blah blah, for
>which the Standard imposes no requirement
>
>Same sentence structure, same idea. It does not say that this behavior
>*must occur* upon use of indeterminately valued objects.
It's the fact that the behaviour *may occur* that makes it
undefined.
Some debugging mallocs allocate and free pages on every request
to ensure that pointers can't be used after storage is freed.
Some architectures have address validation instructions intended
to allow checking that pointers passed from user to system code
are valid within the address space.
An implementation is free to use these facilities to check if
every pointer points to valid storage before any use.
Thanks. Take care, Brian Inglis Calgary, Alberta, Canada
--
Brian....@CSi.com (Brian dot Inglis at SystematicSw dot ab dot ca)
fake address use address above to reply
tos...@aol.com ab...@aol.com ab...@yahoo.com ab...@hotmail.com ab...@msn.com ab...@sprint.com ab...@earthlink.com ab...@cadvision.com ab...@ibsystems.com u...@ftc.gov
spam traps
I've been reading this newsgroup for a while now, and am an amateur C
programmer, but have been getting confused about the evaluation issue
regarding pointers.
It has been said that the simple evaluation of a pointer can cause
indeterminate behaviour. If this is true, how exactly can one do anything
with a pointer? In other words, if merely reading the *value* of the
pointer can cause a program to blow up, how is it possible to test the
pointer using such constructs as:
void *p;
...
if (p==NULL) /* ... */
...
etc.? Am I missing something? I'm sure I am; the Standard is pretty
confusing . . .
Sincerely confused,
Erik Fjeldstrom.
-------------------
Erik Fjeldstrom (fje...@hotmail.com)
"Peter Seebach" <se...@plethora.net> wrote in message
news:3b3d6546$0$324$3c09...@news.plethora.net...
[snip]
I've been reading this newsgroup for a while now, and am an amateur C
programmer, but have been getting confused about the evaluation issue
regarding pointers.
It has been said that the simple evaluation of a pointer can cause
indeterminate behaviour. If this is true, how exactly can one do
anything
with a pointer? In other words, if merely *reading* the value of the
pointer can cause a program to blow up, how is it possible to *test*
the
pointer using such constructs as:
void *p;
...
if (p==NULL) /* ... */
...
etc.? Am I missing something? I'm sure I am; the Standard is pretty
confusing . . .
Sincerely confused,
Erik Fjeldstrom.
-------------------
Erik Fjeldstrom (fje...@hotmail.com)
"Peter Seebach" <se...@plethora.net> wrote in message
news:3b3d6546$0$324$3c09...@news.plethora.net...
[snip]
> I've been reading this newsgroup for a while now, and am an amateur C
> programmer, but have been getting confused about the evaluation issue
> regarding pointers.
>
> It has been said that the simple evaluation of a pointer can cause
> indeterminate behaviour. If this is true, how exactly can one do anything
> with a pointer?
By not doing anything with the pointer before you assign
something to it.
In other words, if merely reading the *value* of the
> pointer can cause a program to blow up, how is it possible to test the
> pointer using such constructs as:
>
> void *p;
> ...
> if (p==NULL) /* ... */
> ...
>
> etc.? Am I missing something? I'm sure I am; the Standard is pretty
> confusing . . .
You're missing the required assignment to the pointer in there,
something like p = &q; or p = malloc (sizeof *p); Once you've
done that, you can use p in all the usual ways. Even if the
malloc() fails, it still assigns a valid pointer (the null
pointer) even though in that case p can't be dereferenced.
An assignment uses `p' as an lvalue (an object) and thus doesn't
reference p's value. There's a difference between an object and
its value.
--
"Some programming practices beg for errors;
this one is like calling an 800 number
and having errors delivered to your door."
--Steve McConnell
I didn't see this being said, and it's wrong in any case. Evaluation of an
indeterminately-valued object causes undefined behavior.
>If this is true, how exactly can one do anything
>with a pointer?
You store a value in it first, then you can use it.
>In other words, if merely reading the *value* of the
>pointer can cause a program to blow up, how is it possible to test the
>pointer using such constructs as:
>
>void *p;
>...
>if (p==NULL) /* ... */
It makes no sense to test a variable that has never received a value.
There are only a few situations in which it's not safe to use a pointer.
When you're in one of those situations, the rule is very simple: don't
use the pointer. It's never really necessary to use a pointer except
when one of those situations does NOT apply. The key ones are:
char *p; /* uninitialized value - don't use. */
char array[sizeof p]="";
p = malloc(sizeof array); /* useable */
free(p); /* indeterminate value - don't use */
p = array; /* useable */
memcpy(&p, array, sizeof(p));
/* indeterminate value - don't use. */
/* p is NOT necessarily null at this point! */
p = array+sizeof(array);
/* safe for comparisons with other pointers, */
/* but don't dereference */
[....]
Sorry, James, I fail to understand some of the lines below, could
you please clarify:
>
> char *p; /* uninitialized value - don't use. */
> char array[sizeof p]="";
ITYM the second line is OK, am I right
>
> p = malloc(sizeof array); /* useable */
> free(p); /* indeterminate value - don't use */
> p = array; /* useable */
>
> memcpy(&p, array, sizeof(p));
Why the &p here?
I think
memcpy(p, array, sizeof p);
is undefined, because p points here to array[0] so source and
destination overlap. OTOH
memmove(p, array, sizeof p);
should be fine, but of course does nothing useful, except maybe in a
memory test.
BTW is memcpy of overlapping arrays really undefined if &array1[0]
== &array2[0] && sizeof array1 == sizeof array2 ?
> /* indeterminate value - don't use. */
> /* p is NOT necessarily null at this point! */
I don't understand the two comments above in the context of the
statements before them
>
> p = array+sizeof(array);
> /* safe for comparisons with other pointers, */
> /* but don't dereference */
That is clear
kind regards
--
Robert Stankowic
pcdo...@netway.at
Correct. I put in comments only where the useability of 'p' changed.
> > p = malloc(sizeof array); /* useable */
> > free(p); /* indeterminate value - don't use */
> > p = array; /* useable */
> >
> > memcpy(&p, array, sizeof(p));
>
> Why the &p here?
That wasn't a typo; that was deliberate. I'm copying into the pointer
itself, not into the place the pointer points to. Hence, the remainder
of your comments about that line of code don't apply.
...
> BTW is memcpy of overlapping arrays really undefined if &array1[0]
> == &array2[0] && sizeof array1 == sizeof array2 ?
Yes. I understand why you might think that safe, but the standard merely
specifies that the objects must not overlap; it doesn't provide an
exception for such cases.
> > /* indeterminate value - don't use. */
> > /* p is NOT necessarily null at this point! */
>
> I don't understand the two comments above in the context of the
> statements before them
That's presumably because you misunderstood my memcpy() call. However,
there's one additional key point behind that statement that you might be
unaware of. The initializer for 'array' guarantees that it would be
filled with '\0'. On many platforms, if you copy such an array into a
pointer, you end up with the same result as p = (char*)0. Some people
are so used to this fact that they think it's required by the standard.
However, the representations of null pointers is implementation-defined,
and (char*)0 doesn't have to have all of it's bits 0. It's not even
guaranteed that all-bits-0 is a valid pointer representation. It could
be a trap representation, hence my statement about "indeterminate
value".
I supposed that, thank you
>
> > > p = malloc(sizeof array); /* useable */
> > > free(p); /* indeterminate value - don't use */
> > > p = array; /* useable */
> > >
> > > memcpy(&p, array, sizeof(p));
> >
> > Why the &p here?
>
> That wasn't a typo; that was deliberate. I'm copying into the
pointer
> itself, not into the place the pointer points to. Hence, the
remainder
> of your comments about that line of code don't apply.
>
I missed that, kind of brain shortcircuit:
"&p yields a pointer to pointer to char, memcpy expects a void *,
different levels of indirection" ...
And I completely missed the context with the zeroed array :-(
> > BTW is memcpy of overlapping arrays really undefined if
&array1[0]
> > == &array2[0] && sizeof array1 == sizeof array2 ?
>
> Yes. I understand why you might think that safe, but the standard
merely
> specifies that the objects must not overlap; it doesn't provide an
> exception for such cases.
I just was not absolutely sure. Thank you for the confirmation
>
> > > /* indeterminate value - don't use. */
> > > /* p is NOT necessarily null at this point! */
> >
> > I don't understand the two comments above in the context of the
> > statements before them
>
> That's presumably because you misunderstood my memcpy() call.
However,
> there's one additional key point behind that statement that you
might be
> unaware of. The initializer for 'array' guarantees that it would
be
> filled with '\0'. On many platforms, if you copy such an array
into a
> pointer, you end up with the same result as p = (char*)0. Some
people
> are so used to this fact that they think it's required by the
standard.
> However, the representations of null pointers is
implementation-defined,
> and (char*)0 doesn't have to have all of it's bits 0. It's not
even
> guaranteed that all-bits-0 is a valid pointer representation. It
could
> be a trap representation, hence my statement about "indeterminate
> value".
Given the explanation about &p that is perfectly clear.
By no means. The memcpy function does indeed expect void *, and void *
is compatible with any kind of object pointer, and p is certainly an
object, and thus &p is an object pointer and is thus compatible with
void *. No difference at all in indirection levels.
--
Richard Heathfield : bin...@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
>On Sun, 01 Jul 2001 00:29:51 +0100, Mark McIntyre <ma...@garthorn.demon.co.uk> wrote:
>> On 30 Jun 2001 23:20:20 GMT,
>> news_comp.std.c_e...@nmhq.net (Niklas Matthies) wrote:
>>
>> >On Sat, 30 Jun 2001 23:56:37 +0100, Mark McIntyre <ma...@garthorn.demon.co.uk> wrote:
>> >> On 29 Jun 2001 17:59:01 -0700, Micah Cowan <mi...@cowanbox.com> wrote:
>> >[毽愍
>> >> >Among other things, this means that all unspecified values are also
>> >> >indeterminate, yet you can determine them
>> >>
>> >> The problem is, you can't determine them without invoking UB....
>> >
>> >You can determine their object representation by inspecting the object's
>> >bytes via unsigned char lvalues.
>>
>> This is true, but in that case you're not examining the object itself.
>
>Of course you do. An object is a contiguous sequence of bytes the
>contents of which can represent values.
No. The bits are not the object (I assume you meant bits not bytes?).
After applying a suitable translation the object is discovered. Your
idea is like saying "by examining some steel and oil, you're examining
the car, because a car is made from that"
>When you talk about "the value
>of an object", you actually mean "the value represented by the bit
>pattern stored into the bytes of an object via an lvalue of some
>specific type" or "the value represented by the bit pattern contained in
>the bytes of an object when accessing it by an lvalue of some specific
>type".
Or "the bits are translated via various techniques into the object"
>An object per se has no type, it only is related to a type with
>respect to a specific access to the object.
An object has a type that you specify when you create it. Sure, you
can create a pointer to the object and cast that pointer to some new
type. All you're doing then is putting a translation layer in place.
For all you know, that layer inverts every 3rd bit.
Well, by saying "No", you're contradicting the standard. That second
sentence was an almost exact quote from section 6.2.6.1p2: "objects are
composed of contiguous sequences of one or more bytes". You might
quibble about the "are composed of" instead of "is", but 3.14p1
clarifies the issue by defining an object as a "region of data storage
in the execution environment, the contents of which can represent
values".
> After applying a suitable translation the object is discovered. Your
> idea is like saying "by examining some steel and oil, you're examining
> the car, because a car is made from that"
The object contains a representation of a value; the translation you
talk about is done in order to determine that value from the
representation. The particular value being represented is determined by
the bits contained in the object, in a particular order. Therefore, a
closer analogy would be to say "by examining the steel and oil that is
currently shaped into a car, I am examining the car". And you know what?
With that improvement in the analogy, the statement doesn't sound
particularly absurd any more.
> >An object per se has no type, it only is related to a type with
> >respect to a specific access to the object.
>
> An object has a type that you specify when you create it. Sure, you
> can create a pointer to the object and cast that pointer to some new
> type. All you're doing then is putting a translation layer in place.
You can create an object without giving it a type; for instance, by
calling malloc.
The type of an object is not a fixed feature of that object. It depends
upon how you access it. See 6.3.2.1p1: "When an object is said to have a
particular type, the type is specified by the lvalue used to designate
the object." Any time that you legally use an lvalue with a different
type to access an object, you've given it a different type. Of course,
with a few special exceptions, the only legal way to read an object is
by using the same type that was used to write to the object. It's that
write which gives the object its type, not the way it was created.
I believe he was saying that '&p' has a different level of indirection
than 'p', and of course he's correct.
I was just describing my "brain shortcircuit" :-)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char *p, *q;
p = malloc(1);
if (p == NULL) {
fprintf(stderr,"Memory allocation failed!\n");
}
q = p;
free(p);
if (memcmp(&p, &q, sizeof(char *))) {
printf("unequal\n");
}
else {
printf("equal\n");
}
exit(EXIT_SUCCESS);
}
That program does not compare the values of the pointers, but only their
bit patterns. The standard allows free() to render the value
indeterminate, but it says nothing about changing the object
representation of that value. Since free() is part of the standard
library, it doesn't have to work like an ordinary function. If the
standard said that the object representation could be changed by free(),
then an implementation would be free to use whatever compiler magic was
needed to make it so. However, in the absence of such a statement, we
have to go by the same rules as ordinary functions, and under those
rules free() doesn't have the right interface to change the pointer; it
would have to accept a void**, not a void*, in order to do that.
However, there is another issue, which has the same effect; q is
required to compare equal to p, but it's not required to contain the
same bit pattern as p. The representation of pointers is implementation
defined, and may include multiple representations of the same pointer
value. The assignment statement could choose to store in q a different
representation of the same value as the one held by p. Therefore, you
could get either "equal" or "unequal", even if you moved the free(p)
after the memcmp() call. However, if you replace the "q = p;" line with
"memcpy(&q,&p,sizeof(q));", then the bit patterns must match after the
memcpy(), and should still match after calling free(). In that case, the
program would be required to print "equal".
Hi Erik
The simple answer is that you can use a pointer when it holds a valid
value.
consider
int *p = NULL;
if (p == NULL) {
[...]
This is OK because p holds a permitted value, as set up by the
programmer.
and
int *p;
p = malloc(sizeof *p);
if (p == NULL) {
[...]
This is OK because the result of calling malloc is documented as either
NULL (no storage available), or a pointer to [sizeof *p] bytes of
storage suitably aligned for any type of object.
The question starting this thread was about the use of a pointer
variable after the value to which it had pointed has been freed (at
which point the pointer value is considered invalid). Ben Pfaff was
asking about an unusual case, which is why there was so much discussion.
As long as you manage your use of pointers properly, you should be able
to test the value of your pointers safely.
The use of invalid (or indeterminate) pointers summed up in the C-FAQ
Question 7.21
http://www.eskimo.com/~scs/C-faq/q7.21.html
Erring on the side of caution, the FAQ suggests it is best not to make
any use of an invalid pointer (we know that the C standard states that
dereferencing an invalid pointer will invoke undefined behaviour, but
the FAQ suggests it is wiser to be more cautious). In fitting with this,
tailoring your example above:
void *p;
... /* p is not altered in this section */
if (p==NULL) /* ... */
this would be a situation to avoid because the value of p is
indeterminate (assuming p is an automatic variable)
Regards
Des Walker
>However, if you replace the "q = p;" line with
>"memcpy(&q,&p,sizeof(q));", then the bit patterns must match after the
>memcpy(), and should still match after calling free(). In that case, the
>program would be required to print "equal".
Hmm... another question... is
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char *p, *q;
p = malloc(1);
if (p == NULL) {
fprintf(stderr,"Memory allocation failed!\n");
}
memcpy(&q, &p, sizeof(char *));
free(q);
exit(EXIT_SUCCESS);
}
OK?
This is not a good example. Even if you remove the free() call, the
program is still free to print "equal" or "unequal", because equality
of value doesn't imply equality of representation (e.g. two 8086 pointers
can point to the same address, while having different segment/offset
combos).
The program can be fixed by copying p to an array of unsigned char before
calling free() and comparing its bytes with those saved in the array after
the free() call. Now, the program must print "equal", because each of
these bytes is an object on its own and the standard guarantees that
a non-volatile object retains its last stored value during its life time.
Dan
--
Dan Pop
CERN, IT Division
Email: Dan...@cern.ch
Mail: CERN - IT, Bat. 31 1-014, CH-1211 Geneve 23, Switzerland
No problem with this. Only the pointer _value_ is relevant for free(),
and memcpy() is intended to preserve the object representation and hence
the value.
-- Niklas Matthies
> On 29 Jun 2001 16:33:42 -0700, Micah Cowan <mi...@cowanbox.com> wrote:
> [毽愍
> > The Standard specifically says that the value of a pointer to an
> > object whose lifetime has expired "becomes indeterminate". It doesn't
> > have to follow normal semantic procedures of macros /or/ functions in
> > order to do that. It has nothing to do with the free() function (or
> > macro) itself, as far as the Standard is concerned. Seems to me an
> > implementation is free to keep track of what pointers point to an
> > object (just as garbage-collecting language implementations do), and
> > set all those pointers to a new value, just because.
>
> I don't think that the fact of the value of some object becoming
> indeterminate allows the implementation to change the object
> representation. At least that's not the intent of the standard, although
> I couldn't find any wording that actually forbids it.
I don't think it's /against/ any intent of the standard. If they had
wanted to forbid an actual change in representation, they certainly
could have done so, but what would the point be? Of what purpose
would it be to ensure that in fact the representation remains the
same, since it is indeterminate? Sure, you could verify that it had
the same representation by using "before" and "after" snapshots in
char arrays, but what use is that? If I should write a C
implementation which does automatically change the representation of
any pointers whose value pointed to an object whose lifetime has now
expired, I should consider myself fully justified to do so. Of
course, in reality, such a task is hardly worthwhile to implement.
> Anyway, this is
> not specific to objects with an indeterminate value; objects with a
> defined value could change their representation as well (as long as the
> value isn't changed by this). For example, in
>
> int i = 5;
> const unsigned char * const p = (const unsigned char *) &i;
> unsigned char x[sizeof(int)];
> int r = 0;
> size_t n;
> for (n = 0; n < sizeof(int); n++) x[n] = p[n];
> for (n = 0; n < sizeof(int); n++) if (x[n] != p[n]) { r = 1; break; }
>
> the standard doesn't seem to actually forbid that r becomes 1 (if there
> is more than one int object representation for 5); but it is very likely
> the intent that it isn't allowed to.
Actually, I'm not too sure about that, either. Making assumptions
that padding bits can't change is certainly not recommended behavior.
And I would be particularly unsympathetic if such code were to
additionally include some explicit access of i between the two for
statements.
Micah
[...]
>What about this, then:
> const int *foo = malloc(sizeof *foo);
> free(foo);
Nit: ITYM
int * const foo = /*etc*/
Regards,
Icarus
--
Experience is the name everyone gives their mistakes.
-Oscar Wilde
A dream of competence, too closely confronted. id...@my-deja.com
Well, the question is not whether it makes sense or does not make sense.
The question is what the standards does guarantee (or is intended to
guarantee) and what it doesn't.
Anyhow, my point was that _if_ the representation is allowed to change,
then this fact doesn't have anything to do with the value having become
indeterminate. If the representation is allowed to change, it already is
allowed to when the value is perfectly determinate.
-- Niklas Matthies
>Mark McIntyre wrote:
>>
>> On 30 Jun 2001 23:57:53 GMT,
>> news_comp.std.c_e...@nmhq.net (Niklas Matthies) wrote:
>...
>> >Of course you do. An object is a contiguous sequence of bytes the
>> >contents of which can represent values.
>>
>> No. The bits are not the object (I assume you meant bits not bytes?).
>
>Well, by saying "No", you're contradicting the standard. That second
>sentence was an almost exact quote from section 6.2.6.1p2: "objects are
>composed of contiguous sequences of one or more bytes".
note the word "bytes" here, not bits.
>You might
>quibble about the "are composed of" instead of "is", but 3.14p1
>clarifies the issue by defining an object as a "region of data storage
>in the execution environment, the contents of which can represent
>values".
I'm not arguing with how objects are stored. We all know that. My
point is, by converting the object to some other type, you may or may
not alter that storage representation.
>> After applying a suitable translation the object is discovered. Your
>> idea is like saying "by examining some steel and oil, you're examining
>> the car, because a car is made from that"
>
>The object contains a representation of a value; the translation you
>talk about is done in order to determine that value from the
>representation. The particular value being represented is determined by
>the bits contained in the object, in a particular order. Therefore, a
>closer analogy would be to say "by examining the steel and oil that is
>currently shaped into a car, I am examining the car". And you know what?
>With that improvement in the analogy, the statement doesn't sound
>particularly absurd any more.
You know what ? It still sounds absurd to me. You examine the steel,
and discover something about the car, other than that its made of
steel? Did you discover the make? or hte engine size?
>> >An object per se has no type, it only is related to a type with
>> >respect to a specific access to the object.
>>
>> An object has a type that you specify when you create it. Sure, you
>> can create a pointer to the object and cast that pointer to some new
>> type. All you're doing then is putting a translation layer in place.
>
>You can create an object without giving it a type; for instance, by
>calling malloc.
Remind me, can you create an object of type "nothing" with malloc, or
must you convert it to a suitable object before use?
>The type of an object is not a fixed feature of that object. It depends
>upon how you access it.
Absolutely. Are we agreeing here?
>See 6.3.2.1p1: "When an object is said to have a
>particular type, the type is specified by the lvalue used to designate
>the object." Any time that you legally use an lvalue with a different
>type to access an object, you've given it a different type.
You're simply agreeing with me here.
>Of course,
>with a few special exceptions, the only legal way to read an object is
>by using the same type that was used to write to the object. It's that
>write which gives the object its type, not the way it was created.
If you write a time_t object to a double, is that OK ? Does it work?
>On Sun, 01 Jul 2001 21:30:38 -0400, "James Kuyper Jr."
><kuy...@wizard.net> wrote:
>
>>Mark McIntyre wrote:
>>>
>>> The bits are not the object (I assume you meant bits not bytes?).
>>
>>Well, by saying "No", you're contradicting the standard. ... "objects
>>are composed of contiguous sequences of one or more bytes".
>
>note the word "bytes" here, not bits.
And?
>>You might
>>quibble about the "are composed of" instead of "is", but 3.14p1
>>clarifies the issue by defining an object as a "region of data storage
>>in the execution environment, the contents of which can represent
>>values".
>
>I'm not arguing with how objects are stored.
Objects aren't stored. Values are stored, in objects. Objects *are* storage.
You seem to be hung up on some abstract notion of "object" that is very
different from C's concrete definition of the term.
>My
>point is, by converting the object to some other type, you may or may
>not alter that storage representation.
Well, that's wrong. A conversion produces a value, that may later be stored in
an object, but by itself it doesn't change anything.
>>You can create an object without giving it a type; for instance, by
>>calling malloc.
>
>Remind me, can you create an object of type "nothing" with malloc,
C's name for "nothing" is "void"; and yes.
>or must you convert it to a suitable object before use?
You must give it a suitable type before using it to store anything. "convert it
to a suitable object" is meaningless.
-- Mat.