From: guenther on 6 May 2010 14:25 On May 6, 8:28 am, William Ahern <will...(a)wilbur.25thandClement.com> wrote: > Geoff Clare <ge...(a)clare.see-my-signature.invalid> wrote: .... > > The dlsym() example in POSIX that uses similar code is a bug in POSIX, > > and is being corrected by this interpretation: > > http://austingroupbugs.net/view.php?id=74#c205 > > which (among many other things) changes the relevant line in the > > example from > > *(void **)(&fptr) = dlsym(handle, "my_function"); > > back to > > fptr = (int (*)(int))dlsym(handle, "my_function"); > > (which is how it was in SUSv2). This might also produce a warning > > in some compilers, but implementations are required to accept it > > and "do the right thing". > > Required by which standard? All conversions from a void pointer to a > function pointer are undefined behavior in C, and all implementations are > required to emit a diagnostic, and allowed to bail. Can you please cite the relevant parts of the C standard that require a diagnostic for that case? When this was most recently discussed on the austin-group mailing list, no one could find such a requirement, while there were agreed to be issues for the *(void **)&fptr from. To pick an apropos message from the archive: https://www.opengroup.org/sophocles/show_mail.tpl?CALLER=show_archive.tpl&source=L&listname=austin-group-l&id=12755 ....though you should examine the entire thread for context. Visit http://www.opengroup.org/austin/mailarchives/ag/ and do a subject search for "0000074". Philip Guenther
From: Ersek, Laszlo on 6 May 2010 15:29 On Thu, 6 May 2010, guenther(a)gmail.com wrote: > On May 6, 8:28�am, William Ahern <will...(a)wilbur.25thandClement.com> > wrote: >> [snip] All conversions from a void pointer to a function pointer are >> undefined behavior in C, and all implementations are required to emit a >> diagnostic, and allowed to bail. > Can you please cite the relevant parts of the C standard that require a > diagnostic for that case? I looked at C99 5.1.1.3 "Diagnostics" and 6.3.2.3 "Pointers". While converting a pointer-to-void to a pointer-to-function is certainly undefined behavior "by the omission of any explicit definition of behavior" (C99 4. "Conformance" p2), I must admit that 6.3.2.3 doesn't contain an explicit "Constraints" part -- like many other sections do (most notably, the descriptions of operators). Therefore, 5.1.1.3 doesn't seem to apply. ----v---- 5.1.1.3 Diagnostics 1 A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. Diagnostic messages need not be produced in other circumstances. [...] ----^---- In short, the explicit conversion (the cast operation) in question is "only" undefined behavior, but (so it seems) not a syntax rule or constraint violation, thus a diagnostic message need not be produced. The current wording of SUSv4 XSH 2.12.3 "Pointer Types" defines the conversion. It likely permits the type-punned pointer access too, by fixing the representation. (Though I'm not sure if an additional note on alignment is not missing.) Cheers, lacos
From: William Ahern on 6 May 2010 17:29 Ersek, Laszlo <lacos(a)caesar.elte.hu> wrote: > On Thu, 6 May 2010, guenther(a)gmail.com wrote: > > On May 6, 8:28?am, William Ahern <will...(a)wilbur.25thandClement.com> > > wrote: > > >> [snip] All conversions from a void pointer to a function pointer are > >> undefined behavior in C, and all implementations are required to emit a > >> diagnostic, and allowed to bail. > > > Can you please cite the relevant parts of the C standard that require a > > diagnostic for that case? > > I looked at C99 5.1.1.3 "Diagnostics" and 6.3.2.3 "Pointers". While > converting a pointer-to-void to a pointer-to-function is certainly > undefined behavior "by the omission of any explicit definition of > behavior" (C99 4. "Conformance" p2), I must admit that 6.3.2.3 doesn't > contain an explicit "Constraints" part -- like many other sections do > (most notably, the descriptions of operators). Therefore, 5.1.1.3 doesn't > seem to apply. <snip> > In short, the explicit conversion (the cast operation) in question is > "only" undefined behavior, but (so it seems) not a syntax rule or > constraint violation, thus a diagnostic message need not be produced. Perhaps. But my take on it was that since the conversion is undefined, what exactly are you assigning? The pointer types in an assignment must be compatible, otherwise it's an express constraint violation. See 6.5.16.1, C99:TC3 draft n1256. If you can't write an expression which is assignable under the constraints of 6.5.16.1, then presumably that requires a diagnostic. 6.5.4, concerning the cast operator, on it's face seems to support the idea that a cast is a declaration of the type, end of story, and any cast to a proper type would be sufficient to meet the contraints of 6.5.16.1, no matter whether the conversion is defined. And I agree this is the intuitive interpretation. But section 6.3 on conversions says that there's nothing special about a cast. Casts can't obtain by _explicit_ conversion what isn't fundamentally convertible; they can only obtain what _implicit_ conversion cannot, and of course there are no implicit conversions between non-void pointers. Without a conversion the type of the expression cannot change, and so you cannot meet the 6.5.16.1 contraints. In support of this latter interpretation, I should note that GCC in pedantic mode does emit a diagnostic. At least according to my local man page, the sole effect of `-pedantic' is to "issue all the warnings demanded by strict ISO C". Though, the diagnostic description concerns the conversion, not the assignment. But if we're concerned with _practical_ interpretations of the standard, rather than _intuitive_, then GCC is persuasive authority. > The current wording of SUSv4 XSH 2.12.3 "Pointer Types" defines the > conversion. It likely permits the type-punned pointer access too, by > fixing the representation. (Though I'm not sure if an additional note on > alignment is not missing.) True. There doesn't seem to be anything else which guarantees that a void pointer doesn't have stricter alignment than a function pointer.
From: Ersek, Laszlo on 6 May 2010 18:49 On Thu, 6 May 2010, William Ahern wrote: > Ersek, Laszlo <lacos(a)caesar.elte.hu> wrote: >> On Thu, 6 May 2010, guenther(a)gmail.com wrote: >>> On May 6, 8:28?am, William Ahern <will...(a)wilbur.25thandClement.com> >>> wrote: >> >>>> [snip] All conversions from a void pointer to a function pointer are >>>> undefined behavior in C, and all implementations are required to emit a >>>> diagnostic, and allowed to bail. >> >>> Can you please cite the relevant parts of the C standard that require a >>> diagnostic for that case? >> >> I looked at C99 5.1.1.3 "Diagnostics" and 6.3.2.3 "Pointers". While >> converting a pointer-to-void to a pointer-to-function is certainly >> undefined behavior "by the omission of any explicit definition of >> behavior" (C99 4. "Conformance" p2), I must admit that 6.3.2.3 doesn't >> contain an explicit "Constraints" part -- like many other sections do >> (most notably, the descriptions of operators). Therefore, 5.1.1.3 doesn't >> seem to apply. > <snip> >> In short, the explicit conversion (the cast operation) in question is >> "only" undefined behavior, but (so it seems) not a syntax rule or >> constraint violation, thus a diagnostic message need not be produced. > > Perhaps. But my take on it was that since the conversion is undefined, I've probably lost the thread of your reasoning, but I believe the point is, the POSIX (SUSv4) XSH 2.12.3 "Pointer Types" section defines both the representation and the conversion (separately). Thus if you take the C99 standard and fill in this single (intentional) white spot, and change nothing else, the resultant specification "fixes" the *only* problem with the expressions in question. > what exactly are you assigning? The pointer types in an assignment must > be compatible, otherwise it's an express constraint violation. The *(void **)&funptr = dlsym(...) assignment has no problems with type compatibility (both sides are of type pointer-to-void), it has problems with representation and alignment (even before funptr is accessed in its own right). They are (or at least, representation is) fixed by POSIX. The funptr = (funptr_type)dlsym(...) assignment has no problem with type compatibility (both sides have type funptr_type), it has problems with undefined conversion. That's also fixed (defined) by POSIX. I believe neither expression violates the constrains of simple assignment. [snip] Cheers, lacos
From: William Ahern on 6 May 2010 20:24
Ersek, Laszlo <lacos(a)caesar.elte.hu> wrote: > On Thu, 6 May 2010, William Ahern wrote: <snip> > > Perhaps. But my take on it was that since the conversion is undefined, > > I've probably lost the thread of your reasoning, but I believe the point > is, the POSIX (SUSv4) XSH 2.12.3 "Pointer Types" section defines both the > representation and the conversion (separately). Thus if you take the C99 > standard and fill in this single (intentional) white spot, and change > nothing else, the resultant specification "fixes" the *only* problem with > the expressions in question. > > > what exactly are you assigning? The pointer types in an assignment must > > be compatible, otherwise it's an express constraint violation. <snip> > funptr = (funptr_type)dlsym(...) > > assignment has no problem with type compatibility (both sides have type > funptr_type), it has problems with undefined conversion. That's also fixed > (defined) by POSIX. > I believe neither expression violates the constrains of simple assignment. My thread of reasoning is that simple assignment of pointers requires compatible _types_, without which a diagnostic is required. In order to get compatible types you need to have a conversion. There's no implicit conversion allowed here, thus you need an explicit conversion--a cast. But a cast can't convert what isn't covertible. There can be no conversion from a void or object pointer to a function pointer. (Note that 6.3.2.3p7 allows conversion between object pointers, so a typical object pointer cast is making a well-defined conversion.) Therefore, there can't be a compatible type to the right operand of the assignment no matter how emphatic the cast, and the assignment constraint can be met. Query: does the following require a diagnostic? struct s { int a; } s; int i; i = (int)s; /* pretty please! */ I propose that the above is indistinguishable in this context from attempting to cast a void pointer to a function pointer. I'm not sure it improves my argument about requiring a diagnostic, but it does a better job of showing what kind of distinctions I'm making. |