This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Serious code generation/optimisation bug (I think)


> No, this is since C90; nothing has changed in this area.  NULL
> doesn't mean "address 0", it means "nothing".  The C statement
> 
>   if (ptr)
> 
> doesn't mean "if ptr does not point to address zero", it means "if ptr
> points to something".

A question then:

How can I make a pointer to point to the integer located at address
0x0? It is a perfectly valid object, it exists, therefore I should be
able to get its address? In fact, if I have a CPU that starts its data
RAM at 0, then the first data object *will* reside at address 0 and
thus taking its address will result in a pointer that has all its bits
clear. Obviously that pointer then should not be equal to NULL, since
it was obtained by taking the address of a valid object, that is, the
pointer indeed points to something. Therefore,

int *a = &first_object;
int *b = (int *) 0;

must result in different values in a and b. Will it?

> I think you perhaps need to be a little less patronizing.

I did not want to be patronising. I wanted to be sarcastic, yes, but
not patronising at all.

> Many of us,
> myself included, have done a great deal of embedded programming and we
> know what the issues are.  You have written an incorrect program, and
> you now know what was incorrect about it.

Yes, I know. However, my problem is not that the program was not
correct. It wasn't and I have admitted it from the beginning. My problem
was that the compiler removed a test on an assumption. It could not
*prove* that the pointer was not NULL. It merely *assumed* it. It can
argue that what I did was wrong, but then it should have told me so. It
did not say anything. It simply decided that since it saw me do
something with a datum, the datum can not possibly be a certain value,
because I should not do that with a datum if it is that certain value.
It was wrong.

If I write

int x[ 10 ];
void foo( int i )
{
   bar( x[ i ] );
   if ( i >= 10 || i < 0 ) { ...

According to the C semantics you shouldn't under or overindex an
array. Thus, you could safely remove the if(). Since I indexed a
10-element array with it, 'i' could not possibly be less than 0 
or more than 9. 

Actually, the pointer (x+13) does not point to any valid object.
Thus, (x+13) == NULL should evaluate true, shouldn't it?

The same elimination should be true to this:

  a = b / c; 
  if ( ! c )

for you can't divide by 0, thus c can not possibly be 0. Does gcc
silently remove the if in the above case?

> > So, pretty please, when the compiler detects that a language
> > resembling to, but not really C is used and removes assumedly
> > (albeit unprovenly) superfluos chunks of code to purify the
> > misguided programmer's intent, could it please at least send a
> > warning?
> 
> In practice that's a lot harder than you might think.  If we were to
> issue a warning for every transformation we made based on the
> semantics of the C language I'm sure people would complain.  "You
> can't dereference a NULL pointer" is a fundamental part of the
> language.

I think I see where your semantics and mine are different:

You say: "You can't dereference a NULL pointer"

I say: "You shouldn't dereference a NULL pointer"

I shouldn't but I most certainly can. I can generate a NULL pointer
where the compiler can not prove (at compile time) that it is NULL. 
If I dereference it, then whatever happens is my problem. I should not
do that but I can and if I do, I take the consequences. The compiler,
in my opinion, must not assume that just because something should not
be done it can not possibly be done. Actually, it should not assume
things at all. Rather, it should prove things before making a
transformation. If it makes a transformation based on nothing more 
than its assumptions, then at least it should give me a warning.

When you eliminate this condition:

unsigned int x;

  if ( x >= 0 ) {

then you are not assuming anything. You know, by definition, that the
condition is true, it's a proven fact. Yet the compiler issues a
warning. 

Or when facing this snipet:

int x, y;

   for ( x = 0 ; x < 10 ; x++ )
     if ( ! x )
        y = 3;
     else
        y = y + x;

the compiler complains that 'y' might be used uninitialised (well, gcc
might be able to work out *that* one but a slightly more complex would
be beyond its reach). Since it could not *prove* that y was on the LHS
before being used on the RHS it issues a warning.

However, when you eliminate this:

    z = *p;

    if ( ! p ) {

you *assume* that p was not NULL, because according to the standard
it should not have been. You have absolutely no way to prove it that
it really wasn't. Yet you eliminate the if() without warning.

See my problem?

Zoltan


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]