This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: Strict aliasing and pointers to functions
- From: Andrew Haley <aph at redhat dot com>
- To: av1474 at comtv dot ru
- Cc: gcc-help at gcc dot gnu dot org
- Date: Sun, 26 Nov 2006 12:41:17 +0000
- Subject: Re: Strict aliasing and pointers to functions
- References: <Pine.LNX.4.64.0611260411320.7920@home.oyster.ru>
av1474@comtv.ru writes:
> I was recently bitten by a piece of code that gcc (3.3.3 and 3.4.1)
> compiled without warnings and which ran just fine, but only on i386,
> on ppc it failed. However on ppc with 3.4.6 the code failed. Reduced
> test case is presented bellow.
>
> <safp.c>
> #include <stdlib.h>
> #include <string.h>
> #include <stdio.h>
> #include <dlfcn.h>
>
> struct {
> void (*fummy) (void);
> void (*dummy) (void);
> void (*tummy) (void);
> } funcs;
>
> void dummy (void)
> {
> }
>
> int main (void)
> {
> printf ("dummy is %p\n", __extension__ (void *) &dummy);
> *(void **) (char **) (void *) &funcs.dummy = dlsym (NULL, "dummy");
Wow.
OK, this is the rule: don't take the address of an lvalue and cast it
to a pointer of a different type. Doing do via (char **) (void *)
doesn't help -- all it can do is silence a useful warning.
> if (!funcs.dummy) {
> printf ("failed %p\n", *(void **) (char **) (void *) &funcs.dummy);
> }
> else {
> printf ("success %p\n", __extension__ (void *) funcs.dummy);
> }
> exit (EXIT_SUCCESS);
> }
> </safp.c>
>
> Addmitedly this is somewhat dodgy, but gcc does not complain even
> with `-Wall', `-W|-Wextra' and `-pedantic'.
You have aked the compiler to warn you about non-ISO operations, and
you then want to perform non-ISO operations without warnings! Make
your mind up!
-pedantic means to complain about non-ISO operations. But ISO doesn't
allow object pointer to function pointer conversions, and that's what
you're doing. So why do you want to use pedantic? The *only* point
of pedantic is to be sure you're writing portable ISO code. But here
you're deliberately writing non-ISO code. It doesn't make sense.
> <transcript-ppc>
> safp$ uname -m
> ppc
> safp$ gcc --version | head -1
> gcc (GCC) 3.4.6
> safp$ gcc -O2 -Wall -W -pedantic safp.c -o safp -ldl -g -Wl,-E
> safp$ ./safp
> dummy is 0x10001778
> failed 0x10001778
> </transcript-ppc>
>
> <transcript-i386>
> safp$ uname -m
> i686
> safp$ gcc --version|head -1
> gcc (GCC) 3.3.3 (SuSE Linux)
> safp$ gcc -O2 -Wall -Werror -W -pedantic -o safp ./safp.c -ldl -Wl,-E
> safp$ ./safp
> dummy is 0x8048700
> success 0x8048700
> safp$ gcc-4.1.0 --version|head -1
> gcc-4.1.0 (GCC) 4.1.0
> safp$ gcc-4.1.0 -O2 -Wall -Werror -Wextra -W -pedantic -o safp ./safp.c -ldl -Wl,-E
> safp$ ./safp
> dummy is 0x80486f0
> success 0x80486f0
> </transcript-i386>
>
> If the code is indeed in error w.r.t. to standard aliasing rules then
> perhaps someone could explain how to fill those pointers to functions
> in some other manner and without resorting to removing -W... flags from
> GCCs command line. Thanks in advance.
union
{
void *barf;
void (*fptr) (void);
} bilge;
bilge.barf = dlsym (NULL, "dummy");
funcs.dummy = bilge.fptr;
> P.S. It seems like i can use the tripple casting trick once again
> instead of straightforward `struct.field', but this again begs
> the question of portability/conformance.
Why are you using the "triple casting trick"? All it can possibly do
is silence a warning; it won't make the code correct.
Andrew.