RFH: aliasing problems

Sergei Organov osv at javad.com
Wed Dec 13 08:28:54 UTC 2006


Steven Johnson
<sjohnson at sakuraindustries.com> writes:

> Sergei Organov wrote:
>> Steven Johnson writes:
>> [...]
>>   
>>> Here is concrete help:
>>>
>>> if_ethersubr.c
>>>
>>> Line 598, 692
>>> sin = (struct sockaddr_in *)&(ifr->ifr_addr);
>>>
>>> change it to
>>> sin = (struct sockaddr_in *)(void*)&(ifr->ifr_addr);
>>>
>>> Line 881:
>>> sa = (struct sockaddr *) & ifr->ifr_data;
>>> to
>>> sa = (struct sockaddr *)(void*) & ifr->ifr_data;
>>>
>>> Why, because C99 says you can turn any pointer to a void* and any void* 
>>> to any other pointer.  This will silence the warning.
>>>     
>>
>> That's exactly what one should never do. Silence compiler warnings by
>> yet another trick will bite us later. Aliasing rules start to play when
>> you *access* actual object by dereferencing the pointer, so any
>> intermediate pointer conversions don't change anything.
>>
>>   
> In principle this is no different to the changes that Joel suggested for 
> the Thread Ready Chain corruption.

No, I don't think so. Joel's suggestion changes the code from one kind
of problematic to a different kind of problematic. For thread ready
chain the solution is IMHO quite simple, -- re-implement it without the
trick of using "compound-overlay" as both the head and the tail of the
list. I seriously doubt anybody will notice any slow-down of RTEMS
because of such change.

For FreeBSD socket code the problem is worse as it seems that not only
its implementation has a lot of violations of the aliasing rules, but
also its interface makes it hard, if at all possible, not to violate the
strict aliasing by using it.

> The fact remains, that the warning does not tell you that there is a 
> problem that will cause broken code, and won't always tell you when the 
> code is broken, such as in my example.

Yes, and GCC folks do confirm that gcc warnings are not entirely
reliable, i.e., they could be both false positives and false
negatives. This makes it even more difficult to fix old code.

> Also, I do not see any way to fix this code otherwise.  The common 
> suggestion of "use a union" instead of this type of "sub typing by 
> pointer casting" is actually not permissible.

Yes, it is not guaranteed to work by the C99 standard, though GCC manual
says it should work in GCC. It's still not ideal, but better than
aliasing problem that is almost guaranteed to break with
-fstrict-aliasing turned on.

[...]

> So I don't see how to "fix" the networking code in any other way than 
> silencing the warning, and ensuring no "constant propogation" can be 
> performed.  I did not see any places where I thought constant 
> propagation could be performed in any of this code.

IMHO, the only practical fix for the networking code is disabling strict
aliasing in compiler by means of -fno-strict-aliasing. I'm afraid that
the amount of changes required to make the networking code to be
aliasing-clean is too high to be practical.

[...]

>> Steven, it seems you still miss the meaning of aliasing rules, so all the
>> suggestions you give are just tricks to silence compiler warnings, not
>> actual fixes to the problems.
>>   
> Please enlighten me as to the meaning of the aliasing rules, in a way 
> that makes sense given the other parts of the specification with regard 
> to permissible pointer conversion.  I would be overjoyed to be 
> enlightened on this matter.

Well, please refer to another my reply to you, where I've tried to shed
some light on this. In particular, I cited the aliasing rules there and
showed that they still allow some code that would be impossible should
pointer conversions be disabled.

I'm not that strong in the interpretation of the aliasing rules myself,
so please don't even try to get my words below as an ultimate truth on
the subject. In particular, GCC 4.1 behavior seems strange to me (see
below), and I'm not sure who is right, me or gcc.

IMHO the main thing to keep in mind is that aliasing rules apply only
when one actually accesses an object through a pointer, and at this
point only the actual type of the object and the type of the pointer
used to access the object do matter. I.e., all the pointer conversions
that might happen in-between have no implications on the
aliasing. Therefore, pointer conversion rules and aliasing rules are
orthogonal to each other.

For example, without pointer conversions, the memcpy() should have been
disallowed, while with current C99 standard it's still valid. Moreover,
GCC folks even suggest to use it in some places that otherwise violate
strict aliasing. Here is an example that demonstrates how memcpy() may
help, and besides it demonstrates how GCC fails to produce a warnings
where IMHO it should, and does produce warnings where I think it should
not:

$ cat alias.c
#include <string.h>

static inline void s1(int* buf, long int val)
{
  *(long int*)buf = val; /* !!! possible aliasing violation */
}

static inline void s2(int* buf, long int val)
{
  memcpy(buf, &val, sizeof(val)); /* OK */
}

long int lbuf[1];
int ibuf[sizeof(long int)/sizeof(int)];
long int v = 10;

void f()
{
  *(long int*)ibuf = v; /* !!! aliasing violation, as we access
                           int object using long int* pointer */
}

void f1()
{
  s1(ibuf, v);         /* !!! aliasing violation, as we access
                          int object using long int* pointer */
}

void f2() {
  s1((int*)lbuf, v);   /* OK, as we access long int object using
                          long int* pointer */
}

void f3()
{
  s2(ibuf, v);         /* OK */
}

void f4()
{
  s2((int*)lbuf, 3);   /* OK */
}

$ gcc-4.1 -W -Wstrict-aliasing=2 -O3 -c alias1.c -o alias1.o
alias1.c: In function `f':
alias1.c:19: warning: dereferencing type-punned pointer will break strict-aliasing rules
alias1.c: In function `f2':
alias1.c:30: warning: dereferencing type-punned pointer will break strict-aliasing rules
alias1.c: In function `f4':
alias1.c:41: warning: dereferencing type-punned pointer will break strict-aliasing rules

As far as I understand, the warning in f() is nice, but then why there
is no warning in f1(), as f() is just the same as f1() with call to s1()
manually inlined?! And warnings in f3() and f4() seem to be bogus.

Please note that the code in s1() either violates the strict aliasing or
not depending on how we call it, and GCC doesn't produce any warning
there 

BTW, at -O3 optimization level GCC seems to be capable to generate the
same nice code for the f3() and f4() routine as it generates for f2().

-- Sergei.




More information about the users mailing list