Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Knowing the implementation, are all undefined behaviours become implementation-defined behaviours?

Reply
Thread Tools

Knowing the implementation, are all undefined behaviours become implementation-defined behaviours?

 
 
Robert Fendt
Guest
Posts: n/a
 
      02-14-2010
And thus spake Ben Bacarisse <(E-Mail Removed)>
Sun, 14 Feb 2010 13:41:23 +0000:

> gcc does exactly that (with certain options). I think this is the
> nature a recent Linux kernel bug: http://lkml.org/lkml/2009/7/6/19


It certainly looks that way. That's a nasty bugger to spot.

> Given the cross-post, I should say that I have no idea if gcc does
> this for the exact case you cite (which is C++) but I wanted to point
> out that similar things are done.


Yes, I did not notice this whole thread had been crossposted to
comp.lang.c; a more appropriate example would then have been a
sizeof(*pointer) or something. Since sizeof in that case relies
only on static type information, one could assume it should work
whether the pointer is null or not. But the dereference itself
already makes the whole programm ill-formed (in case of a
nullpointer).

Regards,
Robert

 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      02-14-2010
On Feb 14, 1:54 pm, Robert Fendt <(E-Mail Removed)> wrote:
> And thus spake Ben Bacarisse <(E-Mail Removed)>
> Sun, 14 Feb 2010 13:41:23 +0000:


> > gcc does exactly that (with certain options). I think this
> > is the nature a recent Linux kernel
> > bug:http://lkml.org/lkml/2009/7/6/19


> It certainly looks that way. That's a nasty bugger to spot.


Either the pointer can be null, or it cannot. If it can be
null, the first unit test which tests it with null should cause
a crash. If it cannot, then the test the g++ would have
removed is superfluous, and removing it shouldn't change
anything.

There are many other cases of undefined behavior which do affect
optimizations, however. Consider an expression like: f((*p)++,
(*q)++). Given this, the compiler "knows" that p and q do not
reference the same memory (since if they did, it would be
undefined behavior), which means that in other code in the
function, the compiler might have cached *p, and knows that it
doesn't have to update or purge its cached value if there is a
write through *q.

> > Given the cross-post, I should say that I have no idea if
> > gcc does this for the exact case you cite (which is C++) but
> > I wanted to point out that similar things are done.


> Yes, I did not notice this whole thread had been crossposted
> to comp.lang.c; a more appropriate example would then have
> been a sizeof(*pointer) or something. Since sizeof in that
> case relies only on static type information, one could assume
> it should work whether the pointer is null or not. But the
> dereference itself already makes the whole programm ill-formed
> (in case of a nullpointer).


Dereferencing a null pointer is only undefined behavior if the
code is actually executed. Something like sizeof(
f(*(MyType*)0) ) is perfectly legal, and widely used in some
template idioms (although I can't think of a reasonable use for
it in C).

--
James Kanze
 
Reply With Quote
 
 
 
 
Malcolm McLean
Guest
Posts: n/a
 
      02-14-2010
On Feb 14, 4:11*pm, James Kanze <(E-Mail Removed)> wrote:
>
> Dereferencing a null pointer is only undefined behavior if the
> code is actually executed. *Something like sizeof(
> f(*(MyType*)0) ) is perfectly legal, and widely used in some
> template idioms (although I can't think of a reasonable use for
> it in C).
>

Nulls are dereferenced to produce the offsetof macro hack in C.

 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      02-14-2010
James Kanze <(E-Mail Removed)> writes:

> On Feb 14, 1:54 pm, Robert Fendt <(E-Mail Removed)> wrote:

<snip>
>> Yes, I did not notice this whole thread had been crossposted
>> to comp.lang.c; a more appropriate example would then have
>> been a sizeof(*pointer) or something. Since sizeof in that
>> case relies only on static type information, one could assume
>> it should work whether the pointer is null or not. But the
>> dereference itself already makes the whole programm ill-formed
>> (in case of a nullpointer).

>
> Dereferencing a null pointer is only undefined behavior if the
> code is actually executed. Something like sizeof(
> f(*(MyType*)0) ) is perfectly legal, and widely used in some
> template idioms (although I can't think of a reasonable use for
> it in C).


For a non-literal null, it is quite common:

new_ptr = realloc(old_ptr, new_length * sizeof *new_ptr);

will work regardless of the state of new_ptr (null, well-defined or
indeterminate).

[I know you know this: I am simple illustrating the point with a
common idiom.]

--
Ben.
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      02-14-2010
On 2010-02-14, Robert Fendt <(E-Mail Removed)> wrote:
> And thus spake Seebs <(E-Mail Removed)>
> 14 Feb 2010 07:03:57 GMT:
>> dereference a null pointer. (For instance, loops which check whether a
>> pointer is null may have the test removed because, if it were null, it
>> would have invoked undefined behavior to dereference it...)


> Sorry to interrupt, but since when is checking a pointer value
> for 0 the same as deferencing it?


It's not.

But if you dereference a pointer at some point, a check against it can
be omitted. If, that is, that dereference can happen without the check.

So imagine something like:

ptr = get_ptr();

while (ptr != 0) {
/* blah blah blah */
ptr = get_ptr();
x = *ptr;
}

gcc might turn the while into an if followed by an infinite loop, because
it *knows* that ptr can't become null during the loop, because if it did,
that would have invoked undefined behavior.

And there are contexts where you can actually dereference a null and not
get a crash, which means that some hunks of kernel code can become infinite
loops unexpectedly with modern gcc. Until the kernel is fixed, which I
believe it has been.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      02-14-2010
On 2010-02-14, James Kanze <(E-Mail Removed)> wrote:
> Either the pointer can be null, or it cannot. If it can be
> null, the first unit test which tests it with null should cause
> a crash. If it cannot, then the test the g++ would have
> removed is superfluous, and removing it shouldn't change
> anything.


Unless you're in a context where dereferencing null exhibits the undefined
behavior of giving you access to a block of memory.

> Dereferencing a null pointer is only undefined behavior if the
> code is actually executed. Something like sizeof(
> f(*(MyType*)0) ) is perfectly legal, and widely used in some
> template idioms (although I can't think of a reasonable use for
> it in C).


Implementation of offsetof(), too, although that's not exactly safe.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / (E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      02-14-2010
Malcolm McLean <(E-Mail Removed)> writes:

> On Feb 14, 4:11*pm, James Kanze <(E-Mail Removed)> wrote:
>>
>> Dereferencing a null pointer is only undefined behavior if the
>> code is actually executed. *Something like sizeof(
>> f(*(MyType*)0) ) is perfectly legal, and widely used in some
>> template idioms (although I can't think of a reasonable use for
>> it in C).
>>

> Nulls are dereferenced to produce the offsetof macro hack in C.


Then I would say that it is not an example of what James was talking
about. In his C++ example, no null pointer is dereferenced.

Obviously there is a terminology issue here in that you might want to
say that sizeof *(int *)0 is a dereference of a null pointer because,
structurally, it applies * to such a pointer; but I would rather
reserve the word dereference for an /evaluated/ application of * (or []
or ->). I'd go so far as to say that any other use is wrong.

--
Ben.
 
Reply With Quote
 
Thad Smith
Guest
Posts: n/a
 
      02-14-2010
Michael Tsang wrote:
>
> Deferencing a NULL pointer is undefined behaviour,


Actually, dereferencing a null pointer _results in_ behavior undefined by
Standard C.

In answer to your subject line question "Knowing the implementation, are all
undefined behaviours become implementation-defined behaviours?", no.

In Standard C "implementation-defined behavior" means that the implementation
documents the behavior. Even if the behavior is consistent for a particular
implementation, it may not be documented.

--
Thad
 
Reply With Quote
 
Richard Tobin
Guest
Posts: n/a
 
      02-14-2010
In article <(E-Mail Removed)>,
Seebs <(E-Mail Removed)> wrote:

> while (ptr != 0) {
> /* blah blah blah */
> ptr = get_ptr();
> x = *ptr;
> }
>
>gcc might turn the while into an if followed by an infinite loop, because
>it *knows* that ptr can't become null during the loop, because if it did,
>that would have invoked undefined behavior.


As I've said before, the fact that the compiler can do this sort of
optimisation is often an indication of an error in the code. Why
would the programmer repeatedly test the pointer if it couldn't be
null? I would much rather that the compiler warned about this, instead
of just treating it as an opportunity to remove some code.

-- Richard
--
Please remember to mention me / in tapes you leave behind.
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      02-14-2010
On 2010-02-14, Richard Tobin <(E-Mail Removed)> wrote:
> As I've said before, the fact that the compiler can do this sort of
> optimisation is often an indication of an error in the code. Why
> would the programmer repeatedly test the pointer if it couldn't be
> null? I would much rather that the compiler warned about this, instead
> of just treating it as an opportunity to remove some code.


That's an interesting point, and I think I'd agree. Maybe. Do we
want a warning for while(1), which we know definitely loops forever?

It could be that the loop was written because the programmer wasn't *sure*
it couldn't be null, but the compiler has proven it and thus feels safe
optimizing.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / (E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Become The master in computer hardware to become successfull shilla Computer Security 1 01-22-2011 06:19 PM
Knowing the implementation, are all undefined behaviours become implementation-defined behaviours? Michael Tsang C Programming 54 03-30-2010 07:46 AM
same code, different providers => different behaviours?? Bart ASP .Net 2 03-22-2007 10:25 AM
"Interesting" C behaviours Rennie deGraaf C Programming 6 11-28-2004 09:27 AM



Advertisments