As originally reported at http://lists.opensuse.org/opensuse-packaging/2010-08/msg00038.html POSIX 2008 says (http://www.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_12_03): "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." When compiling the example code for dlsym (http://www.opengroup.org/onlinepubs/9699919799/functions/dlsym.html) gcc complains with: "warning: dereferencing type-punned pointer will break strict-aliasing rules". Not sure how this applies for C++, but g++ outputs the same warning. The suggested fix is to add a posix/posix2008 mode and make that the default for "platforms that are supposed to be POSIX", specifically Linux.
> "*(void **)(&comp_compress) = dlsym(handle, "comp_compress");" That is not alias safe. Try instead: comp_compress = (__typeof__(comp_compress)) dlsym(handle, "comp_compress"); Which is alias safe. In fact reading what posix standard says it talks about conversion between pointer to function types being safe but not access to a function pointer type via a pointer to void type.
I don't think adding -std=posix is the right solution, since dlsym needs to be usable if users choose other options such as -std=c++0x or -std=gnu99
Yes, POSIX adds additional requirements about pointer representation and conversion, but AFAIK all targets GCC support and have POSIXish runtime satisfy that. The conversion between pointer types is not the problem in your code, it is aliasing violation, and there is nothing in POSIX that says your code is valid.
> Yes, POSIX adds additional requirements about pointer representation and > conversion, but AFAIK all targets GCC support and have POSIXish runtime satisfy > that. The conversion between pointer types is not the problem in your code, it > is aliasing violation, and there is nothing in POSIX that says your code is > valid. Uhm. Sorry, indeed the example code in posix 2008 dlsym() documentation is wrong because of aliasing (where should this be reported? is also wrong in http://www.kernel.org/doc/man-pages/). I was confused because that code was wrong in posix 2004 but the fix from comment #1 was also wrong (not anymore in posix 2008). But using the fix from comment #1 gcc complains with "warning: ISO C forbids conversion of object pointer to function pointer type", at least when using -pedantic. The *message* in the warning is correct. But it is complaining about something that isn't a conversion from "object pointer to function pointer type" but a conversion from "void* pointer to function pointer type", that posix 2008 explicitly allows.
First, yes, the work-around from the official POSIX man-pages is alias-unsafe. They added this example because ISO C doesn't allow conversion of void* pointers to function pointer, but dlsym returns a void* pointer. There are two possibilities to use dlsym: 1) ptrtofntype f = (ptrtofntype) dlsym (...); 2) *(void**)&f = dlsym (...); The former is invalid ISO C (conversion between void* and function pointer not allowed), the latter is invalid ISO C (alias violation). So they were between a rock and a hard place, the dlsym interface was impossible to use with a strict ISO C compiler when it was used to get at addresses of functions. That's why they added language to POSIX 2008 to make conversions between void* and function-pointer types valid. They could have added a new interface in parallel to dlsym that would return a function pointer from the start. Well, they chose to add a new requirement for POSIX systems making variant (1) valid. GCC, at least on POSIX systems, should reflect this, and also make this conversion valid. In fact we're already doing the right thing for such conversions, so we only need to specify that this isn't going to change in the future and disable the warning even in pedantic mode. That means we wouldn't be a strict ISO compiler in this mode anymore. It's what happen when there are two standards in conflict with each other. I think that by default, even with -pedantic, we should not warn for the void* <-> fnptr conversion (note that POSIX only specifically allows the conversion from/to void*, not to any arbitrary data pointer type).
There are more possibilities, like: 3) void (*fnptr) (void); void *p = dlsym (...); memcpy (&fnptr, &p, sizeof (p)); fnptr (); The POSIX standard wording doesn't talk about void * and function pointers being compatible types as used in ISO C99, 6.5. It only talks about the same representation and conversion preserving it. Thus, from this wording, I'd say the 1) is also valid for POSIX, but not 2). When the representation is the same, memcpy should be safe, both from aliasing POV and should DTRT, as workaround for the warning in 1).
Note that this is a common mistake anyways and for example with LTO we unify all pointer alias-sets to that of void *. In fact I proposed that for all languages anyway (look at the hack the C++ FE has for pointer-to-member function pointers for example). So, I'll just take this one and finally commit the pending patch(es).
Well, okay, (3) indeed is valid ISO C (no warning) and works on POSIX 2008. I'd find it very awkward to write such work-around for (1) just so the warning in strict ISO C mode is silenced. I find this case different from other cases where such warnings about standard violations are explicitely wanted even though perhaps the code happens to work. I think it's different from those cases because POSIX (mostly concerned with portability) is a standard too, one that we'd probably like to adhere to on some systems. Hence, I still would suggest to not warn about solution (1), even in ISO C mode.
hit the wrong button, apologies
Not working on the C frontend change. But the warning should be gone on trunk.
This bug in POSIX (recommending the aliasing violation) was fixed. Now they (correctly) recommend the cast. So I think this bug could possibly be closed, unless we want to re-apply it to things like #61739 or perhaps memory-model and synchronization issues.
Closed as fixed in POSIX.