Null Pointer Indirection

L

LJ

I have a doubt that why does the below expression not lead to null
pointer indirection error:

&(*(int * )0);

It runs successfully and evaluates to zero.
 
T

Tobias Blass

) I have a doubt that why does the below expression not lead to null
pointer indirection error:

&(*(int * )0);

It runs successfully and evaluates to zero.

Perhaps the compiler optimized it to (int*)0.
 
L

LJ

Perhaps the compiler optimized it to (int*)0.

So is it implementation-dependent to give an error or not??
An implementation of offsetof() macro uses a technique similar to this
 
E

Eric Sosman

So is it implementation-dependent to give an error or not??

Not implementation-dependent. When the operand of the address-of
operator & is the result of applying the indirection operator *, the
two "cancel each other out" and neither is evaluated. (Section
6.5.3.2 paragraph 3 of the C Standard, if you'd like to look it up.)
An implementation of offsetof() macro uses a technique similar to this

You haven't shown the implementation, but I suspect that if you
examine it closely you'll find there's a little more going on than
just "& swallows *."
 
J

James Kuyper

*x does not dereference a pointer; it converts it into an lvalue. That's why *x
= expr is allowed.

The standard does not use any form of the word "dereference" in any
other part of the standard, except that footnote, so it's arguable what
is meant by that word. However, that footnote is referred to by
6.5.3.2p4: "... If an invalid value has been assigned to the pointer,
the behavior of the unary * operator is undefined.87)"

It is the unary * operator itself which has undefined behavior, not the
assignment operator when it is assigned to. If "the invalid values for
dereferencing a pointer" does not directly refer to "an invalid value"
for which "the behavior of the unary * operator is undefined", then what
is that footnote doing in that position?

In any event, footnotes are not normative; it's not the footnote that
makes the behavior undefined, it merely points out something that can be
derived from the normative text.

6.5.3.2p4 defines the behavior of the unary * operator "If the operand
points to a function...", and "... if it it point to an object ...", but
it provides no definition of the behavior in any other case. A null
pointer doesn't point at anything, neither a function, nor an object, so
the behavior of the unary * operator on such a pointer is undefined "by
the omission of any explicit definition of behavior." (4p2). There are
exceptions when it is not evaluated at all. That occurs when it is the
operand of a & or sizeof operators (6.5.3.2p4 and 6.5.3.4p2, respectively).
 
L

LJ

     Not implementation-dependent.  When the operand of the address-of
operator & is the result of applying the indirection operator *, the
two "cancel each other out" and neither is evaluated.  (Section
6.5.3.2 paragraph 3 of the C Standard, if you'd like to look it up.)


     You haven't shown the implementation, but I suspect that if you
examine it closely you'll find there's a little more going on than
just "& swallows *."

The implementation I am referring is http://c-faq.com/struct/offsetof.html
My doubt is why does accessing the structure member mem using a null
pointer not lead to an error??
 
E

Edward A. Falk

footnote 83)
Among the invalid values for dereferencing a pointer
by the unary * operator
are a null pointer,

Does the standard define "dereference"? In my mind, it means to actually
fetch or store a value from/to the address pointed to by the pointer.

The expression

&(*(int * )0);

never actually transfers any data through a pointer. In English,
it basically means "the address of the data pointed to by the address
zero". That value can be computed without moving any actual data.
 
J

Joe Pfeiffer

LJ said:
The implementation I am referring is http://c-faq.com/struct/offsetof.html
My doubt is why does accessing the structure member mem using a null
pointer not lead to an error??

Because it is never actually dereferenced -- you never actually access
the structure member. The expression calculates what the address would
be if you were to access it (subject to the caveats in the description),
but doesn't do so. A sane compiler will optimize the whole thing away
and replace it with a constant at compile-time!
 
K

Keith Thompson

Does the standard define "dereference"? In my mind, it means to actually
fetch or store a value from/to the address pointed to by the pointer.

The expression

&(*(int * )0);

never actually transfers any data through a pointer. In English,
it basically means "the address of the data pointed to by the address
zero". That value can be computed without moving any actual data.

It *can* be, but in this case it's required to be only because the
standard specifically says so (C99 6.5.3.2p3). That rule doesn't
apply to an otherwise equivalent expression where the "&"'s operand
isn't a "*" operator. For example given:

&(0+*(int*)0);

the compiler is permitted, but not required, to perform a similar
optimization.
 
K

Keith Thompson

LJ said:
The implementation I am referring is http://c-faq.com/struct/offsetof.html
My doubt is why does accessing the structure member mem using a null
pointer not lead to an error??

The definition is:

#define offsetof(type, f) ((size_t) \
((char *)&((type *)0)->f - (char *)(type *)0))

and in fact it *does* lead to undefined behavior (not necessarily to an
error). The rule in 6.5.3.2p3 applies to the expression you posted, but
not to the macro from the FAQ. An implementation can still use this
definition as long as the actual behavior *for that implementation*
matches the requirements for the offsetof() macro.

Which we could have told you if you had posted the expression you were
wondering about in the first place, rather than something "similar".

Incidentally, I find the emphasis in the FAQ a bit odd. The question
is:

How can I determine the byte offset of a field within a structure?

The answer is:

ANSI C defines the offsetof() macro in <stddef.h>, which lets
you compute the offset of field f in struct s as offsetof(struct
s, f). If for some reason you have to code this sort of thing
yourself, one possibility is

#define offsetof(type, f) ((size_t) \
((char *)&((type *)0)->f - (char *)

followed by an explanation of its non-portability. But in practice, all
C implementations provide offsetof(). (Something that doesn't provide
offsetof() is not a C implementation.)

(There may be ancient pre-ANSI C implementations that don't provide
offsetof(); for almost all practical purposes, they're not worth
worrying about.)
 
J

J. J. Farrell

Keith said:
...
Incidentally, I find the emphasis in the FAQ a bit odd. The question
is:

How can I determine the byte offset of a field within a structure?

The answer is:

ANSI C defines the offsetof() macro in <stddef.h>, which lets
you compute the offset of field f in struct s as offsetof(struct
s, f). If for some reason you have to code this sort of thing
yourself, one possibility is

#define offsetof(type, f) ((size_t) \
((char *)&((type *)0)->f - (char *)

followed by an explanation of its non-portability. But in practice, all
C implementations provide offsetof(). (Something that doesn't provide
offsetof() is not a C implementation.)

(There may be ancient pre-ANSI C implementations that don't provide
offsetof(); for almost all practical purposes, they're not worth
worrying about.)

.... but they certainly were worth worrying about at the time that answer
was written.
 
K

Keith Thompson

J. J. Farrell said:
... but they certainly were worth worrying about at the time that answer
was written.

I don't question that it was valid when it was written, I just suggest
that it needs updating.
 
A

Angel

But ... and here is my question ... is there any requirement that
dereferencing a NULL pointer create a detectable error? Or is this
implementation and system dependent?

The standard only states that this produces undefined behaviour. Most
implementations throw a runtime exception.
And is the compiler _required_ to detect an obvious NULL dereference?

Nope.

Out of curiosity, I did a quick test which shows me that gcc doesn't
catch an obvious null pointer dereference, not even with -Wall -pedantic.
It does result in a segfault at runtime.
 
J

Joe Pfeiffer

Datesfat Chicks said:
Your code suggests another question, which perhaps another poster can
answer.

I would guess that the C standards require that NULL be distinct from
the addresses of any variables or a value that can be returned by
malloc() and friends indicating success.

But ... and here is my question ... is there any requirement that
dereferencing a NULL pointer create a detectable error? Or is this
implementation and system dependent?

It (almost) has to be implementation-dependant: systems with no memory
protection can't reasonably throw an error (one could generate code that
would perform an explicit check for NULL on every pointer dereference,
but that would have unacceptable costs).

Ancient history: for years years I thought that a NULL pointer was a
valid representation of an empty string. The reason for this error was
that on the first Unix system I spent any significant time working with
(a VAX running BSD) address 0 was user-readable, and always contained a
0. I learned my mistake when I moved to a Sun workstation and a lot of
code broke....
And is the compiler _required_ to detect an obvious NULL dereference?

No. To the best of my knowledge (though there are people here who know
much better than I) there is no requirement that the compiler anticipate
any run-time errors.
 
S

Shao Miller

Your code suggests another question, which perhaps another poster can
answer.

I would guess that the C standards require that NULL be distinct from
the addresses of any variables or a value that can be returned by
malloc() and friends indicating success.

But ... and here is my question ... is there any requirement that
dereferencing a NULL pointer create a detectable error? Or is this
implementation and system dependent?

And is the compiler _required_ to detect an obvious NULL dereference?

I've asked about this before.

'NULL' is a null pointer constant, which can most certainly be detected
at translation time.

A null pointer value, on the other hand, might only be detectable at
execution-time.

Either way, application of unary '*' or '->' leads to undefined
behaviour, which an implementation might provide some meaning for, or
might choose to provide a message about.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,952
Messages
2,570,111
Members
46,692
Latest member
NewtonChri

Latest Threads

Top