Bug 45289 - gcc lacks a "posix" option for "-std" since POSIX 2008 defines special behavior
Summary: gcc lacks a "posix" option for "-std" since POSIX 2008 defines special behavior
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.5.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-08-15 19:28 UTC by Cristian Morales Vega
Modified: 2014-07-08 09:22 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-08-15 21:38:37


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Cristian Morales Vega 2010-08-15 19:28:04 UTC
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.
Comment 1 Andrew Pinski 2010-08-15 19:31:10 UTC
> "*(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.
Comment 2 Jonathan Wakely 2010-08-15 19:38:40 UTC
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
Comment 3 Jakub Jelinek 2010-08-15 19:47:30 UTC
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.
Comment 4 Cristian Morales Vega 2010-08-15 20:21:09 UTC
> 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.
Comment 5 Michael Matz 2010-08-15 21:07:11 UTC
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).
Comment 6 Jakub Jelinek 2010-08-15 21:33:59 UTC
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).
Comment 7 Richard Biener 2010-08-15 21:38:37 UTC
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).
Comment 8 Michael Matz 2010-08-16 00:55:16 UTC
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.
Comment 9 Ralf Wildenhues 2010-08-16 15:05:27 UTC
hit the wrong button, apologies
Comment 10 Richard Biener 2010-08-27 19:25:49 UTC
Not working on the C frontend change.  But the warning should be gone on trunk.
Comment 11 Rich Felker 2014-07-08 00:37:58 UTC
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.
Comment 12 Richard Biener 2014-07-08 09:22:27 UTC
Closed as fixed in POSIX.