Shao Miller <> writes:
> On 1/21/2013 15:17, Keith Thompson wrote:
>> Shao Miller <> writes:
>>> On 1/21/2013 01:02, Keith Thompson wrote:
>>>> 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.
>>>
>>> Which is why I wrote "relative to the goal of indirect access."
>>
>> Comparing a pointer to NULL, if you don't know in advance that it's
>> either a null pointer or a valid pointer to some object, does not meet
>> "the goal of indirect access". The phrase "relative to the goal of
>> indirect access" is meaningless in this context, or just plain wrong.
>> You might as well talk about "comparing an integer to zero relative to
>> the goal of determining whether it's even".
>
> status_t some_func(input_t * input, output_t ** output) {
> output_t * new_item;
> status_t status;
>
> /* Do stuff. Populate 'new_item', 'status' */
>
> if (output) {
> /* Caller wants to refer to the result */
> *output = new_item;
> }
> return status;
> }
>
> Here, if 'output' does not compare equal to a null pointer, we'll
> attempt indirection on it. If the caller passed an argument for
> 'output' which they believed to be one of {null pointer, pointer to an
> object}, then our test here yields a false positive for the latter if
> what they actually passed was the third possibility: A non-null pointer
> to no object.
Right, because, as I said, checking whether a pointer is null does not
reliably check whether it may be dereferenced. It's a false negative
for the question "May I safely dereference this pointer?". It's not a
false negative for the question "Is this a null pointer?"
The test yields a false negative because it's not a valid test for what
it's trying to test. (No such valid test is possible in portable C.)
>>> - VA32: Any pointer type with a representation that is 32 bits and
>>> which has no trap representations.
>>
>> What makes you think that 32-bit pointers on MS Windows have no
>> trap representations? `(void*)0x0000000C` almost certainly is a
>> trap representation for the implementation in question. (I'm using
>> the phrase "trap representation" as the C standard uses it; I lack
>> interest in any other meanings *unless* some documentation uses
>> that exact phrase with a different meaning.)
>
> Well I didn't quite say that. I was referring to a particular subset of
> 32-bit pointers. I would certainly consider the representation
> 0x00000001 to be a trap representation for an 'int *' in 32-bit Windows.
Yes, you did quite say that. You said the pointer type "has no trap
representations".
> For VA32 (which would correspond to 'void *', 'char *', etc.), the
> reason I would think that is that I've over a decade of use, I guess. I
> could be wrong! But here's a starting-point, perhaps:
>
> http://msdn.microsoft.com/en-us/library/k26sa92e.aspx
That looks a lot like the C Standard's requirements for pointer
conversions, with some extra information about how Microsoft's compiler
performs such conversions. Unlike the standard, it doesn't mention trap
representations.
>>> - Unsafe pointer: Any pointer having a VA32 type and having a value
>>> that does not refer to any object. If such a pointer value is used in
>>> an attempt to access the stored value of a pointed-to object, the
>>> behaviour is undefined.
>>
>> Such a pointer value is either a null pointer or a trap representation.
>>
>
> Wait, are you saying that any pointer that does not match one of {null
> pointer, points to an object} must necessarily be a trap representation?
I believe so, yes.
Given a pointer value that is neither a null pointer nor a pointer to an
object, what criteria would cause you to claim that it's *not* a trap
representation?
>>> But who cares?
}
>>
>> I no longer do. Whatever relevant claims you were making, you've now
>> quietly backed away from them.
>
> I haven't intentionally backed away from any claims. I wish I knew what
> claims you might be referring to.
>
> If you're asking about "null pointer", I thought Mr. Philip Lantz
> already answered that when he said: "This traps in the debugger, and the
> debugger reports a "null pointer dereference" at address 0x0000000c."
I don't remember that particular statement. It's been a long thread.
/* Let struct foo have a member m at offset 12 (0xc) */
struct foo *ptr = NULL;
do_something_with(foo->m);
The evaluation of `foo->m` has undefined behavior because the value of
`foo` is a null pointer. It's likely that the generated code will take
the value stored in `foo` (0x00000000), add the offset 12 to it
(yielding 0x0000000c), and then attempt to dereference the resulting
pointer value. If the program is being executed under the debugger,
this is likely to cause a trap. The debugger sees an attempt to
dereference address 0x0000000c and, quite reasonably, infers that it was
probably the result of accessing a member of a structure or class, at an
offset of 12 bytes, via a null pointer. The debugger may well have
other information available that makes that inference stronger.
(Conceivably a compiler could generate code to test the value of ptr
against 0x00000000 before attempting to add the offset to it; that could
catch the error slightly sooner and more directly, but at a considerable
performance cost.)
I believe you've been implying that this means that 0x0000000c is
a null pointer. It isn't. Seeing Philip's remark, quoted above,
it's a little clearer why you might have thought so.
[snip]
A pointer with the value 0x0000000c is not a null pointer, nor does it
point to any object. It is, I believe, a trap representation. In
certain contexts, the existence of such a pointer may imply that there's
been an attempt to dereference a null pointer; the null pointer itself
(in this particular implementation) has the representation 0x00000000.
Finally, a correction to something I may or may not have implied
earlier. Creating such a pointer, by evaluating `(void*)0x0000000c`,
does not itself have undefined behavior; 6.3.2.3p5 says that the
conversion may yield a trap representation, not that the conversion
itself has undefined behavior. Any attempt to *use* such a pointer
value does have undefined behavior.
0x0000000c;
/* obviously ok, no UB */
(void*)0x0000000c;
/* Creates a trap representation, then discards it; no UB */
p = (void*)0x0000000c;
/* Attempts to access a trap representation, UB */
if ((void*)0x0000000c) == NULL) ...
/* UB */
It's very likely that the third statement will quietly store the
expected value in `p`, and that the last will evaluate the condition as
false; these are entirely consistent with the behavior being undefined.
--
Keith Thompson (The_Other_Keith)
kst- <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"