[union] Pointers to inherited structs are valid ?

  • Thread starter Maciej Labanowicz
  • Start date
S

Shao Miller

I can imagine a system that masks off some bits before comparing
it to NULL. Not that I know any that actually do it.

Yes well that's along the lines that it might be. For example, if a
'free'd pointer becomes 0x0000000C, in C terminology, it'd be an
"indeterminate value." But, using C terminology again, it'd be an
"unspecified value" rather than a "trap representation", as the value
can be read and passed around. In C terminology, it would "point to no
object", just as a "null pointer" does. Upon dereferencing though,
Windows could tell from the representation just what the problem was:
Use of a 'free'd pointer. And yes, the higher bits might indicate that
it was a pointer that points to no object ("null class", perhaps we
could call it).
 
P

Philip Lantz

Keith said:
When you say it "behaves as a null pointer in C code", what exactly do
you mean by that?

Does it compare equal to NULL? If not, then it *doesn't* behave as a
null pointer in C code.

I would guess that he's seeing something like the following:

struct {
int a, b, c, d;
} *p = NULL;

p->d = 0;

This traps in the debugger, and the debugger reports a "null pointer
dereference" at address 0x0000000c.
 
S

Shao Miller

I would guess that he's seeing something like the following:

struct {
int a, b, c, d;
} *p = NULL;

p->d = 0;

This traps in the debugger, and the debugger reports a "null pointer
dereference" at address 0x0000000c.

Indeed! Or, perhaps more commonly:

typedef struct { UINT32 A, B, C, D; } FOO, * PFOO;

PUINT32 GetFooD(PFOO foo) {
return &foo->D;
}

(I don't particularly like pointer typedefs, but pretend they're
Microsoft's.)

Then the caller dereferences the returned pointer, or passes it around
until some other function does. That is, I find that it's not usually
quite as obvious as in your example, and sometimes due to opacity or
abstraction.

(And thanks for the set-up for the function name; I'm hungry. :) )
 
K

Keith Thompson

Shao Miller said:
Yes well that's along the lines that it might be. For example, if a
'free'd pointer becomes 0x0000000C, in C terminology, it'd be an
"indeterminate value."
[...]

How does a free'd pointer *become* anything?

For example:

int *p = malloc(sizeof *p);
// Assume malloc() succeeded
// Assume the representation of p, when viewed as
// bytes, is 0x12, 0x34, 0x56, 0x78
free(p);
// Any attempt to refer to the value of p has undefined behavior.
// But if you examine its representation, say by type-punning it
// as an array of unsigned char, it will still look like
// 0x12, 0x34, 0x56, 0x78

The argument to free() is passed *by value*, so free() can't modify the
contents of the pointer object. The argument needn't even be an lvalue;
free(p + 1 - 1) is perfectly valid.

An implementation *could* do some sort of compiler magic, changing the
representation of a pointer object passed to free(), but (a) I don't
think it would be worth the effort, and (b) it's not clear that it would
even be conforming (the bytes making up the representation of the
pointer are objects in their own right, whose values don't change unless
you write to them). In any case, I'm not aware that Microsoft's
implementation does this -- nor am I aware that it implements "==" on
pointers so that anything other that all-bits-zero would compare equal
to NULL.

There are a lot of strange things an implementation *could* do, but the
topic at hand is what a particular implementation actually does.
Storing some specific byte sequence in uninitialized objects is a great
idea, but it doesn't have much to do with null pointers as C defines the
term.
 
S

Shao Miller

Shao Miller said:
Yes well that's along the lines that it might be. For example, if a
'free'd pointer becomes 0x0000000C, in C terminology, it'd be an
"indeterminate value."
[...]

How does a free'd pointer *become* anything?

The value of a pointer becomes indeterminate at the end of the
pointed-to object's lifetime. Defect Report #260 discusses this.

Windows "Checked" builds are more easily debugged than their "Free"
counterparts. I don't think a freed pointer's representation changing
is beyond the realm of either possible or useful. But "might," above,
means that this was just a guess, which now seems likely to be wrong,
thanks to Mr. Philip Lantz' more obvious explanation.

However, the masking of bits that Mr. Glen Herrmannsfeldt mentioned
still seems about right. Here is another guess: The "null class
pointer" that WinDbg talks about is some reasonably-sized window around
the unsigned value 0. Given a null pointer of all-zeroes, the
'CONTAINING_RECORD' macro could yield, let's say, 0xFFFFFFF0. Mr.
Lantz' example shows the other direction.
[...]

There are a lot of strange things an implementation *could* do, but the
topic at hand is what a particular implementation actually does.
Storing some specific byte sequence in uninitialized objects is a great
idea, but it doesn't have much to do with null pointers as C defines the
term.

Which of these most closely resembles the pointer value 0x0000000C in
this Windows scenario?:

1. A trap representation for some pointer type, invoking UB when read
2. A valid value for some pointer type; pointing to an object
3. A null pointer; pointing to no object, invoking UB when dereferenced

If it doesn't compare equal to 'NULL', then it doesn't appear to match
any of these. But if we can fuzz our way from Standard theory to
real-world practice, we might note some similarities to #3.

Perhaps interestingly, Mr. Lantz' explanation actually means the
representation gives hints about which member of a structure was
involved in a bug. In Windows, many "object types" (not to be confused
with the C notions) are C structures beginning with a common initial
sequence. A "bad" pointer might reveal which member of this common
initial sequence was involved in a bug. :) This isn't the "pointer was
freed" guess of above, but still useful!

(By the way, I've asked in another forum about possible documentation
for NULL_CLASS_PTR_DEREFERENCE, although I don't know if you or anyone
else cares.)
 
K

Keith Thompson

Shao Miller said:
On 1/19/2013 23:03, Keith Thompson wrote: [...]
There are a lot of strange things an implementation *could* do, but the
topic at hand is what a particular implementation actually does.
Storing some specific byte sequence in uninitialized objects is a great
idea, but it doesn't have much to do with null pointers as C defines the
term.

Which of these most closely resembles the pointer value 0x0000000C in
this Windows scenario?:

1. A trap representation for some pointer type, invoking UB when read
2. A valid value for some pointer type; pointing to an object
3. A null pointer; pointing to no object, invoking UB when dereferenced

If it doesn't compare equal to 'NULL', then it doesn't appear to match
any of these. But if we can fuzz our way from Standard theory to
real-world practice, we might note some similarities to #3.

It could easily be #1. For example, if a type `struct foo` has a
member `bar` at offset 12 (0xC), and a `struct foo*` object `ptr`
that has a null pointer value, then `&(ptr->bar)` could easily have
a representation that looks like 0x0000000C.

[...]
(By the way, I've asked in another forum about possible documentation
for NULL_CLASS_PTR_DEREFERENCE, although I don't know if you or anyone
else cares.)

The name NULL_CLASS_PTR_DEREFERENCE wouldn't necessarily refer to
a *null pointer*.

I don't think there's anything strange going on here. None of the
exotic possibilities permitted by the standard (null pointers with a
representation other than all-bits-zero, pointer objects changing
representation after being passed to free(), pointers with different
representations appear to be equal) appear to be happening.
 
S

Shao Miller

It could easily be #1. For example, if a type `struct foo` has a
member `bar` at offset 12 (0xC), and a `struct foo*` object `ptr`
that has a null pointer value, then `&(ptr->bar)` could easily have
a representation that looks like 0x0000000C.

It could be #1, but it isn't #1 in this Windows scenario. Using such a
pointer value doesn't yield undefined behaviour until it's dereferenced.
It'll still compare as unequal with valid pointer values, can still be
assigned to a pointer, etc.
[...]
(By the way, I've asked in another forum about possible documentation
for NULL_CLASS_PTR_DEREFERENCE, although I don't know if you or anyone
else cares.)

The name NULL_CLASS_PTR_DEREFERENCE wouldn't necessarily refer to
a *null pointer*.

It depends on the definition. For the C definition, if it doesn't
compare equal to 'NULL', then it's probably not a null pointer, as you
pointed out earlier. For WinDbg users, it probably is. Hopefully I'll
find out just what Microsoft has to say about it.
I don't think there's anything strange going on here. None of the
exotic possibilities permitted by the standard (null pointers with a
representation other than all-bits-zero, pointer objects changing
representation after being passed to free(), pointers with different
representations appear to be equal) appear to be happening.

I agree with you about this; seems pretty straight-forward. I had
wondered about the observed representation 0x0000000C (given Geoff's
post about trap representations[1]), but I'm sure Mr. Lantz' explanation
is right and that this is not such a case.

[1] (Not to be confused with the C definition, but simply meaning a
representation which the debugger can trap/detect.)
 
B

Ben Bacarisse

Shao Miller said:
It could be #1, but it isn't #1 in this Windows scenario. Using such
a pointer value doesn't yield undefined behaviour until it's
dereferenced. It'll still compare as unequal with valid pointer
values, can still be assigned to a pointer, etc.

All of that seems to be entirely consistent with #1.

Talking about whether something is UB in "this Windows scenario" looks
very odd to me because the term UB is defined by the language, not the
implementation. If the language says something is UB then it is and you
can't conclude from the behaviour of an implementation that it isn't.
All behaviours are consistent with UB.

<snip>
 
P

Philip Lantz

Shao said:
It could be #1, but it isn't #1 in this Windows scenario. Using such a
pointer value doesn't yield undefined behaviour until it's dereferenced.
It'll still compare as unequal with valid pointer values, can still be
assigned to a pointer, etc.

The undefined behavior occurred when &ptr->bar was executed (with ptr
equal to NULL). You cannot refer to the language definition to make
sense of anything that happens after that.
 
K

Keith Thompson

Shao Miller said:
It could be #1, but it isn't #1 in this Windows scenario.

I believe it is.
Using such a
pointer value doesn't yield undefined behaviour until it's dereferenced.

Yes, it does. Concretely:

int main(void) {
struct foo {
char c[12];
int i;
};

struct foo *fptr = NULL;

int *iptr = &(fptr->i);

return 0;
}

The evaluation of the expression `&(fptr->i)` has undefined behavior.
If you disagree, please show me where the standard defines its
behavior.

If the observed behavior is that the representation 0x0000000C is stored
in `iptr`, that doesn't mean the behavior is defined.
It'll still compare as unequal with valid pointer values, can still be
assigned to a pointer, etc.

It happens to do so in the implementation we're discussing, and probably
in most implementations.
[...]
(By the way, I've asked in another forum about possible documentation
for NULL_CLASS_PTR_DEREFERENCE, although I don't know if you or anyone
else cares.)

The name NULL_CLASS_PTR_DEREFERENCE wouldn't necessarily refer to
a *null pointer*.

It depends on the definition. For the C definition, if it doesn't
compare equal to 'NULL', then it's probably not a null pointer, as you
pointed out earlier.

A pointer that doesn't compare equal to NULL *definitely* isn't a null
pointer, by the definition of pointer equality in N1570 6.5.9p6.
(Unless the program's behavior is undefined for other reasons, in which
case anything goes.)
For WinDbg users, it probably is. Hopefully I'll
find out just what Microsoft has to say about it.

I don't believe so. As far as I can see, the only evidence you've
presented that this thing is a "null pointer" is the identifier
"NULL_CLASS_PTR_DEREFERENCE".

What I believe that name implies is that the pointer value whose
representation looks like 0x0000000C was most likely created as
the result of a null pointer. It doesn't imply that 0x0000000C
is itself a null pointer. Nobody other than you is saying that.
(Unless you can produce some Microsoft documentation that uses the
phrase "null pointer" -- with no other words between "null" and
"pointer" -- to refer to such a pointer value.)
 
S

Shao Miller

All of that seems to be entirely consistent with #1.

I made the mistake of saying "undefined behaviour" there, instead of
"unexpected behaviour." My point was that the unexpected only manifests
from a _dereference_, rather than a _read_.
Talking about whether something is UB in "this Windows scenario" looks
very odd to me because the term UB is defined by the language, not the
implementation. If the language says something is UB then it is and you
can't conclude from the behaviour of an implementation that it isn't.

<snip>

Agreed, and it's supposed to be odd. This discussion is pretty useless
though, because no matter how many times I try to suggest considering "C
definitions" versus "practiced usage," nobody quite seems to; possibly
because the latter is uninteresting to them, or because this Windows
case is uninteresting to them, or because I make mistakes like the above
without qualifying each term as "not to be confused with the C
definition". I thought it would be an easy discussion; it isn't. My
mistake.

And agreed again; we all [ought to] know:
All behaviours are consistent with UB.

Thankfully, 3 people have now made it abundantly clear that comparing C
terminology to subjects outside of C is not going to be fruitful. :)
 
S

Shao Miller

The undefined behavior occurred when &ptr->bar was executed (with ptr
equal to NULL). You cannot refer to the language definition to make
sense of anything that happens after that.

Agreed; my mistake. I should not have typed "undefined behaviour," but
"unexpected behaviour." I guess it wasn't obvious that I was trying to
discuss a bit "outside the box" from the C definitions.

As you point out:

&ptr->bar
&((*ptr).bar)
^^^^------ C UB
 
B

Ben Bacarisse

Shao Miller said:
I made the mistake of saying "undefined behaviour" there, instead of
"unexpected behaviour." My point was that the unexpected only
manifests from a _dereference_, rather than a _read_.

How far back? In how many posts must I substitute "unexpected
behaviour" for "undefined behaviour" in order to determine your meaning?
Have you said what "unexpected behaviour" is? Does it depend on who is
doing the expecting? Does any meaning survive after addressing these
questions?
Agreed, and it's supposed to be odd. This discussion is pretty
useless though, because no matter how many times I try to suggest
considering "C definitions" versus "practiced usage," nobody quite
seems to; possibly because the latter is uninteresting to them, or
because this Windows case is uninteresting to them, or because I make
mistakes like the above without qualifying each term as "not to be
confused with the C definition". I thought it would be an easy
discussion; it isn't. My mistake.

But you seem to make the same mistake when explicitly using C's terms
and without any of the "unexpected/undefined" madness above. E.g.:

| For example, if a free'd pointer becomes 0x0000000C, in C terminology,
| it'd be an "indeterminate value." But, using C terminology again,
| it'd be an "unspecified value" rather than a "trap representation", as
| the value can be read and passed around.

This suggest that you think it can't be a trap representation because it
can be read and passed around. A trap representation is nothing more
than a representation that does not denote a valid value for the type
in question. The effect of using it can be entirely benign.
And agreed again; we all [ought to] know:
All behaviours are consistent with UB.

Thankfully, 3 people have now made it abundantly clear that comparing
C terminology to subjects outside of C is not going to be fruitful. :)

Are you not using C's terms in the quote above?
 
S

Shao Miller

How far back?

Probably 12 posts back from this one I'm typing now; sorry.
In how many posts must I substitute "unexpected
behaviour" for "undefined behaviour" in order to determine your meaning?

5 of mine; sorry.
Have you said what "unexpected behaviour" is?

Not explicitly, no. I thought it would be obvious that it was the
context of a Windows debugger notifying the programmer, since Geoff had
just discussed that.
Does it depend on who is
doing the expecting?

Not really. If the program operates as expected without the debugger
interrupting, that's probably commonly desired by different programmers.
Does any meaning survive after addressing these
questions?

Yes, I think so. Having seen these answers, do you? :)
But you seem to make the same mistake when explicitly using C's terms
and without any of the "unexpected/undefined" madness above. E.g.:

| For example, if a free'd pointer becomes 0x0000000C, in C terminology,
| it'd be an "indeterminate value." But, using C terminology again,
| it'd be an "unspecified value" rather than a "trap representation", as
| the value can be read and passed around.

This suggest that you think it can't be a trap representation because it
can be read and passed around. A trap representation is nothing more
than a representation that does not denote a valid value for the type
in question. The effect of using it can be entirely benign.

I'm sorry you interpreted it that way. Would it be best to surround
every paragraph of every response with context, to prevent
misunderstanding? In that quote, I thought it was obvious that this was
in the context of using a Microsoft debugger, where the behaviour would
agree with the semantics of an "unspecified value"; not warning the
programmer during a read of the value (which it _could_).

In the summary below, I hope it's clear that a recurring theme was to
establish 0x0000000C as some kind of a trap value, so the quote above
doesn't match with that without deciding that it needs additional context.

Here's a summary of how the conversation has gone, from my perspective.
All quotes are fictional, and names have been omitted:

Me: "If an uninitialized 'unsigned char' can have a trap representation,
then...[something]"

A: "Whatever it has isn't a trap representation, you idiot. It might
not even have a value."

Me: "Why wouldn't it have a value? Is it because it might not
successfully translate? Ok, what about in this code example where it
does translate?"

B: "What would you say it has?"

Me: "An [C] indeterminate value and a magic property \"uninitialized\".
Here's some history, since you asked what I would say..."

B: "Here are Microsoft's documented [non-C] trap values..."

Me: "Nice summary! Say, isn't there another one, 0x0000000C, as a
[non-C] trap for [non-C] null pointers? I don't remember..."

C: "Oh no, that wouldn't be a [C] null pointer."

Me: "Yes, well I was talking about B's [non-C] trap values. I see a
Microsoft debugger catch these things and call them [non-C] null pointers."

C: "A [C] null pointer isn't a [C] trap representation. Does this thing
behave like a [C] null pointer?"

Me (intended): "Well it only behaves badly upon dereferencing."

C: "If it's not a [C] null pointer, then it shouldn't be called one, and
it's off-topic."

D: "There could be multiple [C] null pointer representations."

Me (missing C's cue to drop it): "That could be. Maybe the bits have
something to do with useful debug-info, such as a 'free'd pointer."

C: "That seems unlikely, due to pass-by-value. We're still not talking
about [C] null pointers if it doesn't behave like a [C] null pointer."

Me: "Agreed; it doesn't match. So what's the closest thing,
behaviour-wise? It seems like a [C] null pointer, in some ways."

C: "It could be closest to a [C] trap representation. It seems pretty
straight-forward."

Me (intended): "Well for those who observe 0x0000000C in a Microsoft
debugger, the program behaves well until it's dereferenced, so it's not
closest to a [C] trap representation, but to a [C] null pointer."

You: "It could be closest to a [C] trap representation. And don't say
\"undefined behavour\" if you don't mean it."

Me: "Oops. True."
And agreed again; we all [ought to] know:
All behaviours are consistent with UB.

Thankfully, 3 people have now made it abundantly clear that comparing
C terminology to subjects outside of C is not going to be fruitful. :)

Are you not using C's terms in the quote above?

Yes I was, but it only makes for confusion, so I'll try to avoid that.
 
K

Keith Thompson

Shao Miller said:
I'm very glad you think so. I guess that means it resembles Geoff's
explanation of "trap representations" (not to be confused with the C
definition).

I'm not going to go back in this thread to figure out what Geoff's
explanation of "trap representations" is supposed to be.

[...]
I don't quite understand your use of "definitely" when I had said "If it
doesn't compare equal to 'NULL', then it doesn't appear to match any of
these. But if we can fuzz our way from Standard theory to real-world
practice..." Was this unclear?

There's nothing fuzzy about any of this. A pointer value is a null
pointer if and only if it compares equal to NULL.
But anyway, sure. So you'd say that this dissimilarity weighs enough
that it's closer to #1, and that it's not particularly relevant or
interesting to ask which of the three is a close match, because of the
earlier undefined behaviour. Ok!

As I mentioned before, one of the difficulties for a _programmer_ is
that sometimes _they_get_ these pointers from OS functions, without
having obviously invoked C's UB. Because they can read, assign, and
pass these pointers without unexpected behaviour, it's not like a
signalling NaN, or an integer with improper parity.

The C standard does not define the behavior of OS functions. Therefore
a call to an OS function has undefined behavior.
I don't know what you think I'm trying to prove. Are you pointing out
that when I said "WinDbg absolutely calls it a null pointer," I haven't
backed that up?

I don't recall you using those exact words, but yes, if you're saying
that WinDbg calls it a null pointer, you haven't backed it up.

Are you in fact claiming that WinDbg calls this a "null pointer"? If
so, please prove it.
When programming for the Windows NT kernel, if a pointer is C's 'NULL'
or 0x0000000C, it crashes the computer when it is used for indirect
access, as neither refers to a valid C object.

So there's some similarity of behavior between a null pointer
(0x00000000 for this implementaiton) and a particular non-null pointer
representation (0x0000000C).
Reading, storing,
passing these values do not crash the computer.

One of the myriad possible consequences of undefined behavior.
What is the practical
difference for an NT driver developer? That they don't compare as equal
with value but only with behaviour? Comparing with 'NULL' yields a
false negative relative to the goal of indirect access. No?

No.

Ignoring for the moment the fact that you can't create or access
that value without having invoked undefined behavior:

The expression `(void*)0x0000000C == NULL` yields 0 (false).
This is not a "false negative"; it's a perfectly correct result
indicating that `(void*)0x0000000C` is not a null pointer.

If you want to determine whether a given pointer value may be safely
dereferenced, comparing it to NULL is not the way to do that.

Please be clear: what exactly are you claiming?
 
G

glen herrmannsfeldt

(snip)
So there's some similarity of behavior between a null pointer
(0x00000000 for this implementaiton) and a particular non-null pointer
representation (0x0000000C).
(snip)

The expression `(void*)0x0000000C == NULL` yields 0 (false).
This is not a "false negative"; it's a perfectly correct result
indicating that `(void*)0x0000000C` is not a null pointer.

I would try memcpy() of the 0x0000000C into a pointer variable,
and then compare it to NULL.
If you want to determine whether a given pointer value may be safely
dereferenced, comparing it to NULL is not the way to do that.
Please be clear: what exactly are you claiming?

-- glen
 
J

James Kuyper

I would try memcpy() of the 0x0000000C into a pointer variable,
and then compare it to NULL.

How? NULL is the name of a macro which must expand into a null pointer
constant. It therefore cannot be an lvalue (at least in C - in C++ the
rules are different), and therefore cannot be compared using memcpy().

I suppose you could define two pointer variables, store 0xC into one,
and the expansion of NULL into the other. However, The result of storing
NULL into a pointer variable need not have a unique representation; it
could sometimes be represented by 0, and other times by 0xC. The results
could easily vary depending upon the type of the pointer variable. Less
likely, but still permitted by the standard, is the possibility that you
get a different null pointer representation each time the assignment is
executed.

More importantly, why would you do it that way? The standard says
nothing about what the results of that comparison should be, and the
results of that comparison have nothing to do with the defined behavior
of null pointers. The only testable behavior associated uniquely with
null pointers is that they all compare equal to each other, and unequal
to any pointer to an actual object or function.
Now, if two valid pointers of the same type have the same
representation, they must compare equal, but the converse is not true.
 
B

Ben Bacarisse

James Kuyper said:
How? NULL is the name of a macro which must expand into a null pointer
constant. It therefore cannot be an lvalue (at least in C - in C++ the
rules are different), and therefore cannot be compared using memcpy().

Presumably that last "memcpy"is a typo. You presumably meant "and
therefore cannot be compared using memcmp()" but why do you think that's
what glen herrmannsfeldt (sic) meant? He is suggesting using memcpy to
get the desired representation into a pointer object and then using ==
to see if it compares equal to a null pointer.

<snip>
 
K

Keith Thompson

James Kuyper said:
How? NULL is the name of a macro which must expand into a null pointer
constant. It therefore cannot be an lvalue (at least in C - in C++ the
rules are different), and therefore cannot be compared using memcpy().

I think you've misread what glen wrote (memcpy vs. memcmp?). I believe
he meant something like this:

uintptr_t x = 0x0000000C;
void *ptr;
memcpy(&ptr, &x, sizeof ptr);
if (ptr == NULL) { ... }

But I don't think glen's suggestion is particularly relevant to
the current discussion. It would be for an implementation in which
pointer-to-integer conversion did something other than just copying
the bits, but I don't believe the implementation we're dealing with
(Microsoft's) does that.

The standard permits all sorts of exotic pointer behavior:
null pointers with representations other than all-bits-zero,
pointer conversions that do something other than just copying
or reinterpreting the representation, equality operators that
do something other than a simple bit-by-bit comparison, etc.
And any of those things could lead to a pointer with the same
representation as the integer 0x0000000C being a null pointer.
As far as I know, Microsoft's implementation doesn't do any of
these things; a pointer value with an all-bits-zero representation
is the one and only null pointer for a given pointer type, a pointer
whose representation looks like 0x0000000C is not a null pointer, and
nothing in Microsoft's documentation refers to it as a null pointer.
(Code that dereferences a pointer with that representation is
reasonably assumed, by the debugger, to be the result of referring
to a member of a structure "pointed to" by a null pointer.)

Or perhaps I've misunderstood the point Shao Miller is trying
to make.
 
B

Ben Bacarisse

Shao Miller said:
Probably 12 posts back from this one I'm typing now; sorry.


5 of mine; sorry.


Not explicitly, no. I thought it would be obvious that it was the
context of a Windows debugger notifying the programmer, since Geoff
had just discussed that.

I don't recall Geoff saying that anything was unexpected. That's your
phrase that you admit you have not defined. I can't fathom what you
think is unexpected behaviour or what point that would made. Should I
be able to work it out?

Geoff's post looks simple and correct: the standard permits trap
representations that produce undefined behaviour so an implementation is
permitted to use special values to trigger interesting effects (either
in a debugger or else where).
Not really. If the program operates as expected without the debugger
interrupting, that's probably commonly desired by different
programmers.


Yes, I think so. Having seen these answers, do you? :)

No. I have no idea what your point is anymore.
I'm sorry you interpreted it that way. Would it be best to surround
every paragraph of every response with context, to prevent
misunderstanding?

No I read in context and try to respond in context as well. I don't
think I missed the context.
In that quote, I thought it was obvious that this
was in the context of using a Microsoft debugger, where the behaviour
would agree with the semantics of an "unspecified value"; not warning
the programmer during a read of the value (which it _could_).

It could be an unspecified value (you are explicitly using C terms here)
if it is a valid pointer value. It may well be. Is it? It may equally
well not be. It could be either a trap representation or an unspecified
value but you seem to suggest that it is one not the other. You seem to
suggest that one possibility is more likely than the other for reasons
that are spurious. The best evidence that it might not be a trap
representation is that it's a valid pointer, but you give no evidence for
that -- quite the contrary in fact.
In the summary below, I hope it's clear that a recurring theme was to
establish 0x0000000C as some kind of a trap value, so the quote above
doesn't match with that without deciding that it needs additional
context.

Here's a summary of how the conversation has gone, from my
perspective. All quotes are fictional, and names have been omitted:

Me: "If an uninitialized 'unsigned char' can have a trap
representation, then...[something]"

A: "Whatever it has isn't a trap representation, you idiot. It might
not even have a value."

Me: "Why wouldn't it have a value? Is it because it might not
successfully translate? Ok, what about in this code example where it
does translate?"

B: "What would you say it has?"

Me: "An [C] indeterminate value and a magic property
\"uninitialized\". Here's some history, since you asked what I would
say..."

B: "Here are Microsoft's documented [non-C] trap values..."

If this was Geoff, he correctly called then "trap representation"
(rather than values) and he referred to "they" meaning the C committee.
He was talking at C trap representations not "[non-C] trap values".
Me: "Nice summary! Say, isn't there another one, 0x0000000C, as a
[non-C] trap for [non-C] null pointers? I don't remember..."

C: "Oh no, that wouldn't be a [C] null pointer."

Me: "Yes, well I was talking about B's [non-C] trap values. I see a
Microsoft debugger catch these things and call them [non-C] null
pointers."

I think you missed Geoff's point.
C: "A [C] null pointer isn't a [C] trap representation. Does this
thing behave like a [C] null pointer?"

Me (intended): "Well it only behaves badly upon dereferencing."

C: "If it's not a [C] null pointer, then it shouldn't be called one,
and it's off-topic."

D: "There could be multiple [C] null pointer representations."

Me (missing C's cue to drop it): "That could be. Maybe the bits have
something to do with useful debug-info, such as a 'free'd pointer."

C: "That seems unlikely, due to pass-by-value. We're still not
talking about [C] null pointers if it doesn't behave like a [C] null
pointer."

Me: "Agreed; it doesn't match. So what's the closest thing,
behaviour-wise? It seems like a [C] null pointer, in some ways."

C: "It could be closest to a [C] trap representation. It seems pretty
straight-forward."

Me (intended): "Well for those who observe 0x0000000C in a Microsoft
debugger, the program behaves well until it's dereferenced, so it's
not closest to a [C] trap representation, but to a [C] null pointer."

You: "It could be closest to a [C] trap representation. And don't say
\"undefined behavour\" if you don't mean it."

Me: "Oops. True."
And agreed again; we all [ought to] know:

All behaviours are consistent with UB.

Thankfully, 3 people have now made it abundantly clear that comparing
C terminology to subjects outside of C is not going to be fruitful. :)

Are you not using C's terms in the quote above?

Yes I was, but it only makes for confusion, so I'll try to avoid that.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
474,077
Messages
2,570,566
Members
47,202
Latest member
misc.

Latest Threads

Top