[opensuse-packaging] strict-aliasing and dlsym
Hi, I'm getting "comp.c:42:3: warning: dereferencing type-punned pointer will break strict-aliasing rules" that translates to "I: Program is likely to break with new gcc. Try -fno-strict-aliasing. W: sipp strict-aliasing-punning comp.c:42, 46, 50" through post-build-checks. The thing is the offending code is "*(void **)(&comp_compress) = dlsym(handle, "comp_compress");" And the man page of dlsym explicitly says that is the correct way to do it: /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos"); would seem more natural, but the C99 standard leaves casting from "void *" to a function pointer undefined. The assignment used below is the POSIX.1-2003 (Technical Corrigendum 1) workaround; see the Rationale for the POSIX specification of dlsym(). */ So, the question: could gcc -O2 really break that code? Or that's a false warning and I can be 100% safe ignoring it? Thanks. -- To unsubscribe, e-mail: opensuse-packaging+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-packaging+help@opensuse.org
El 13/08/10 13:44, Cristian Morales Vega escribió:
Hi,
I'm getting "comp.c:42:3: warning: dereferencing type-punned pointer will break strict-aliasing rules"
that translates to
"I: Program is likely to break with new gcc. Try -fno-strict-aliasing. W: sipp strict-aliasing-punning comp.c:42, 46, 50"
through post-build-checks.
The thing is the offending code is
"*(void **)(&comp_compress) = dlsym(handle, "comp_compress");"
And the man page of dlsym explicitly says that is the correct way to do it:
/* Writing: cosine = (double (*)(double)) dlsym(handle, "cos"); would seem more natural, but the C99 standard leaves casting from "void *" to a function pointer undefined. The assignment used below is the POSIX.1-2003 (Technical Corrigendum 1) workaround; see the Rationale for the POSIX specification of dlsym(). */
So, the question: could gcc -O2 really break that code? Or that's a false warning and I can be 100% safe ignoring it?
Even the example code in the manual triggers the warning, matz will probably know where the bug really is ;) -- To unsubscribe, e-mail: opensuse-packaging+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-packaging+help@opensuse.org
On Fri, 13 Aug 2010 19:44:38 +0200, Cristian Morales Vega <cmorve69@yahoo.es> wrote:
The thing is the offending code is
"*(void **)(&comp_compress) = dlsym(handle, "comp_compress");"
So, the question: could gcc -O2 really break that code? Or that's a false warning and I can be 100% safe ignoring it?
Yes, it can. The C compiler assumes the normal aliasing rules, i.e. that objects of one type can only be accessed through pointers of the same type or char/void pointers. Therefor the compiler will organize the code depending on whether it finds other accesses or not. And before you remark it, there is a difference between 'void **' and 'void *' and the standard does only cover 'void *'. The only way I know of to correct the code would be to use a union, i.e. for the csine example { void *handle; double (*cosine)(double); char *error; union{ void *vp; double (*cos)(double); }pun. handle = dlopen("libm.so", RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); } dlerror(); /* Clear any existing error */ pun.vp = dlsym(handle, "cos); cosine = pun.cos. if ((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); exit(EXIT_FAILURE); } GCC guarantees that the union trick works. Philipp -- To unsubscribe, e-mail: opensuse-packaging+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-packaging+help@opensuse.org
2010/8/14 Philipp Thomas <Philipp.Thomas2@gmx.net>:
On Fri, 13 Aug 2010 19:44:38 +0200, Cristian Morales Vega <cmorve69@yahoo.es> wrote:
The thing is the offending code is
"*(void **)(&comp_compress) = dlsym(handle, "comp_compress");"
So, the question: could gcc -O2 really break that code? Or that's a false warning and I can be 100% safe ignoring it?
Yes, it can. The C compiler assumes the normal aliasing rules, i.e. that objects of one type can only be accessed through pointers of the same type or char/void pointers. Therefor the compiler will organize the code depending on whether it finds other accesses or not.
And before you remark it, there is a difference between 'void **' and 'void *' and the standard does only cover 'void *'. The only way I know of to correct the code would be to use a union, i.e. for the csine example
{ void *handle; double (*cosine)(double); char *error; union{ void *vp; double (*cos)(double); }pun.
handle = dlopen("libm.so", RTLD_LAZY);
if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); }
dlerror(); /* Clear any existing error */
pun.vp = dlsym(handle, "cos); cosine = pun.cos.
if ((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); exit(EXIT_FAILURE); }
GCC guarantees that the union trick works.
a) I hate the world b) It worked, thanks. Since I'm going to bookmark this for future reference, for completeness: any idea about if this is different in C++? Is there "void *" to a function pointer defined? Also, I'm not sure about how the Single UNIX Specification, IEEE and The Open Group are mixed. But at http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html it says "Due to the problem noted here, a future version may either add a new function to return function pointers, or the current interface may be deprecated in favor of two new functions: one that returns data pointers and the other that returns function pointers." And at the header it says "IEEE Std 1003.1, 2004 Edition". Wikipedia says there exists POSIX:2008... so, there is any new function that returns function pointers? -- To unsubscribe, e-mail: opensuse-packaging+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-packaging+help@opensuse.org
2010/8/14 Cristian Morales Vega <cmorve69@yahoo.es>:
Also, I'm not sure about how the Single UNIX Specification, IEEE and The Open Group are mixed. But at http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html it says
"Due to the problem noted here, a future version may either add a new function to return function pointers, or the current interface may be deprecated in favor of two new functions: one that returns data pointers and the other that returns function pointers."
And at the header it says "IEEE Std 1003.1, 2004 Edition". Wikipedia says there exists POSIX:2008... so, there is any new function that returns function pointers?
This happens to me for using too much Google. The latest version is at http://www.opengroup.org/onlinepubs/9699919799/functions/dlsym.html What they finally did was adding this to POSIX 2008: "2.12.3 Pointer Types All function pointer types shall have the same representation as the type pointer to void. Conversion of a function pointer to void * shall not alter the representation. A void * value resulting from such a conversion can be converted back to the original function pointer type, using an explicit cast, without loss of information. Note: The ISO C standard does not require this, but it is required for POSIX conformance." So gcc is C99 compliant but not POSIX 2008 compliant (and gcc's man doesn't shows any posix option for -std). Someone feels like opening a bug report for this to gcc? I don't have the standards knowledge that will be needed when people starts to argue if POSIX should be dictating compilers behavior. And it seems the "void **" vs "void *" thing Philipp commented still applies... And http://gcc.gnu.org/ doesn't works right now, and interpret that as a fate's warning :-p -- To unsubscribe, e-mail: opensuse-packaging+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-packaging+help@opensuse.org
Hi, On Sun, 15 Aug 2010, Cristian Morales Vega wrote:
http://www.opengroup.org/onlinepubs/9699919799/functions/dlsym.html What they finally did was adding this to POSIX 2008:
"2.12.3 Pointer Types
All function pointer types shall have the same representation as the type pointer to void. Conversion of a function pointer to void * shall not alter the representation. A void * value resulting from such a conversion can be converted back to the original function pointer type, using an explicit cast, without loss of information.
Note: The ISO C standard does not require this, but it is required for POSIX conformance."
Ahh, so they finally did something about this problem, I wasn't aware of this.
So gcc is C99 compliant but not POSIX 2008 compliant (and gcc's man doesn't shows any posix option for -std). Someone feels like opening a bug report for this to gcc? I don't have the standards knowledge that will be needed when people starts to argue if POSIX should be dictating compilers behavior.
It should on platforms that are supposed to be POSIX. Meaning that GCC should have a mode for POSIX compliance and further that this mode should be default on Linux. The technical change necessary for this is fairly small. Ciao, Michael. -- To unsubscribe, e-mail: opensuse-packaging+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-packaging+help@opensuse.org
2010/8/15 Michael Matz <matz@suse.de>:
On Sun, 15 Aug 2010, Cristian Morales Vega wrote:
So gcc is C99 compliant but not POSIX 2008 compliant (and gcc's man doesn't shows any posix option for -std). Someone feels like opening a bug report for this to gcc? I don't have the standards knowledge that will be needed when people starts to argue if POSIX should be dictating compilers behavior.
It should on platforms that are supposed to be POSIX. Meaning that GCC should have a mode for POSIX compliance and further that this mode should be default on Linux. The technical change necessary for this is fairly small.
OK. It's now gcc bug #45289. -- To unsubscribe, e-mail: opensuse-packaging+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-packaging+help@opensuse.org
participants (4)
-
Cristian Morales Vega
-
Cristian Rodríguez
-
Michael Matz
-
Philipp Thomas