* clumsy cast in dlopen.3
@ 2026-05-14 10:56 Bruno Haible
2026-05-14 11:29 ` Alejandro Colomar
0 siblings, 1 reply; 9+ messages in thread
From: Bruno Haible @ 2026-05-14 10:56 UTC (permalink / raw)
To: linux-man
The dlopen.3 man page contains this text:
*(void **) &cosine = dlsym(handle, "cos");
This (clumsy) cast conforms with the ISO C standard and will
avoid any compiler warnings.
However, such a cast violates the strict aliasing rules of ISO C, no?
The proper workaround is to use a union:
union { double (*cosine) (double); void *pointer; } u;
u.pointer = dlsym(handle, "cos");
...
printf("%f\n", u.cosine(2.0));
Bruno
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: clumsy cast in dlopen.3 2026-05-14 10:56 clumsy cast in dlopen.3 Bruno Haible @ 2026-05-14 11:29 ` Alejandro Colomar 2026-05-15 8:35 ` AW: " Walter Harms 0 siblings, 1 reply; 9+ messages in thread From: Alejandro Colomar @ 2026-05-14 11:29 UTC (permalink / raw) To: Bruno Haible; +Cc: linux-man, Martin Uecker [-- Attachment #1: Type: text/plain, Size: 897 bytes --] Hi Bruno, On 2026-05-14T12:56:55+0200, Bruno Haible wrote: > The dlopen.3 man page contains this text: > > *(void **) &cosine = dlsym(handle, "cos"); > > This (clumsy) cast conforms with the ISO C standard and will > avoid any compiler warnings. > > However, such a cast violates the strict aliasing rules of ISO C, no? I think I agree. Dereferencing the pointer &cosine with a type different than the type of the object is not allowed. I've CCed Martin, who might be able to confirm. > > The proper workaround is to use a union: > > union { double (*cosine) (double); void *pointer; } u; > > u.pointer = dlsym(handle, "cos"); > ... > printf("%f\n", u.cosine(2.0)); This is seems much better, indeed. Have a lovely day! Alex > > Bruno > > > > -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* AW: clumsy cast in dlopen.3 2026-05-14 11:29 ` Alejandro Colomar @ 2026-05-15 8:35 ` Walter Harms 2026-05-15 9:56 ` Alejandro Colomar 0 siblings, 1 reply; 9+ messages in thread From: Walter Harms @ 2026-05-15 8:35 UTC (permalink / raw) To: Alejandro Colomar, Bruno Haible; +Cc: linux-man@vger.kernel.org, Martin Uecker Hello, I agree the cast is not nice, (someone for a extension of C standard ?) but i have to admit that i have never seen the trick with the union. But it needs some explaination. The comment in the example is already huge, i would ask for a comment subsektion for this behavier here. btw: the original code in the example looks like this ... cosine = (typeof(double (double)) *) dlsym(handle, "cos"); my2c wh ________________________________________ Von: Alejandro Colomar <alx@kernel.org> Gesendet: Donnerstag, 14. Mai 2026 13:29:20 An: Bruno Haible Cc: linux-man@vger.kernel.org; Martin Uecker Betreff: Re: clumsy cast in dlopen.3 Hi Bruno, On 2026-05-14T12:56:55+0200, Bruno Haible wrote: > The dlopen.3 man page contains this text: > > *(void **) &cosine = dlsym(handle, "cos"); > > This (clumsy) cast conforms with the ISO C standard and will > avoid any compiler warnings. > > However, such a cast violates the strict aliasing rules of ISO C, no? I think I agree. Dereferencing the pointer &cosine with a type different than the type of the object is not allowed. I've CCed Martin, who might be able to confirm. > > The proper workaround is to use a union: > > union { double (*cosine) (double); void *pointer; } u; > > u.pointer = dlsym(handle, "cos"); > ... > printf("%f\n", u.cosine(2.0)); This is seems much better, indeed. Have a lovely day! Alex > > Bruno > > > > -- <https://www.alejandro-colomar.es> ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: AW: clumsy cast in dlopen.3 2026-05-15 8:35 ` AW: " Walter Harms @ 2026-05-15 9:56 ` Alejandro Colomar 2026-05-15 14:05 ` Martin Uecker 0 siblings, 1 reply; 9+ messages in thread From: Alejandro Colomar @ 2026-05-15 9:56 UTC (permalink / raw) To: Walter Harms; +Cc: Bruno Haible, linux-man@vger.kernel.org, Martin Uecker [-- Attachment #1: Type: text/plain, Size: 2361 bytes --] Hi Walter, On 2026-05-15T08:35:49+0000, Walter Harms wrote: > Hello, > I agree the cast is not nice, (someone for a extension of C standard ?) > but i have to admit that i have never seen the trick with the union. > But it needs some explaination. The comment in the example is already huge, > i would ask for a comment subsektion for this behavier here. The thing about unions is that the only two ways for type punning that are blessed by ISO C are unions and memcpy(3). Everything else isn't allowed. Perfectly valid: static_assert(sizeof(int) == sizeof(float)); union u {int i; float f;}; float f; union u u; u.i = 42; f = u.f; Perfectly valid: static_assert(sizeof(int) == sizeof(float)); int i; float f; i = 42; memcpy(&f, &i, sizeof(float)); UB: static_assert(sizeof(int) == sizeof(float)); int i; float f; i = 42; f = *(float *) &i; Have a lovely day! Alex > btw: the original code in the example looks like this ... > cosine = (typeof(double (double)) *) dlsym(handle, "cos"); > > my2c > wh > > ________________________________________ > Von: Alejandro Colomar <alx@kernel.org> > Gesendet: Donnerstag, 14. Mai 2026 13:29:20 > An: Bruno Haible > Cc: linux-man@vger.kernel.org; Martin Uecker > Betreff: Re: clumsy cast in dlopen.3 > > Hi Bruno, > > On 2026-05-14T12:56:55+0200, Bruno Haible wrote: > > The dlopen.3 man page contains this text: > > > > *(void **) &cosine = dlsym(handle, "cos"); > > > > This (clumsy) cast conforms with the ISO C standard and will > > avoid any compiler warnings. > > > > However, such a cast violates the strict aliasing rules of ISO C, no? > > I think I agree. Dereferencing the pointer &cosine with a type > different than the type of the object is not allowed. I've CCed Martin, > who might be able to confirm. > > > > > The proper workaround is to use a union: > > > > union { double (*cosine) (double); void *pointer; } u; > > > > u.pointer = dlsym(handle, "cos"); > > ... > > printf("%f\n", u.cosine(2.0)); > > This is seems much better, indeed. > > > Have a lovely day! > Alex > > > > > Bruno > > > > > > > > > > -- > <https://www.alejandro-colomar.es> -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: AW: clumsy cast in dlopen.3 2026-05-15 9:56 ` Alejandro Colomar @ 2026-05-15 14:05 ` Martin Uecker 2026-05-15 15:15 ` Alejandro Colomar 2026-05-15 15:41 ` [PATCH v1] man/man3/dlopen.3: EXAMPLES: Simplify use of dlsym(3) Alejandro Colomar 0 siblings, 2 replies; 9+ messages in thread From: Martin Uecker @ 2026-05-15 14:05 UTC (permalink / raw) To: Alejandro Colomar, Walter Harms; +Cc: Bruno Haible, linux-man@vger.kernel.org There is no such thing needed here, you just do double (*cosine)(double); cosine = dlsym(handle, "cos"); Best, Martin Am Freitag, dem 15.05.2026 um 11:56 +0200 schrieb Alejandro Colomar: > Hi Walter, > > On 2026-05-15T08:35:49+0000, Walter Harms wrote: > > Hello, > > I agree the cast is not nice, (someone for a extension of C standard ?) > > but i have to admit that i have never seen the trick with the union. > > But it needs some explaination. The comment in the example is already huge, > > i would ask for a comment subsektion for this behavier here. > > The thing about unions is that the only two ways for type punning that > are blessed by ISO C are unions and memcpy(3). Everything else isn't > allowed. > > Perfectly valid: > > static_assert(sizeof(int) == sizeof(float)); > > union u {int i; float f;}; > > float f; > union u u; > > u.i = 42; > f = u.f; > > Perfectly valid: > > static_assert(sizeof(int) == sizeof(float)); > > int i; > float f; > > i = 42; > memcpy(&f, &i, sizeof(float)); > > UB: > > static_assert(sizeof(int) == sizeof(float)); > > int i; > float f; > > i = 42; > f = *(float *) &i; > > > Have a lovely day! > Alex > > > btw: the original code in the example looks like this ... > > cosine = (typeof(double (double)) *) dlsym(handle, "cos"); > > > > my2c > > wh > > > > ________________________________________ > > Von: Alejandro Colomar <alx@kernel.org> > > Gesendet: Donnerstag, 14. Mai 2026 13:29:20 > > An: Bruno Haible > > Cc: linux-man@vger.kernel.org; Martin Uecker > > Betreff: Re: clumsy cast in dlopen.3 > > > > Hi Bruno, > > > > On 2026-05-14T12:56:55+0200, Bruno Haible wrote: > > > The dlopen.3 man page contains this text: > > > > > > *(void **) &cosine = dlsym(handle, "cos"); > > > > > > This (clumsy) cast conforms with the ISO C standard and will > > > avoid any compiler warnings. > > > > > > However, such a cast violates the strict aliasing rules of ISO C, no? > > > > I think I agree. Dereferencing the pointer &cosine with a type > > different than the type of the object is not allowed. I've CCed Martin, > > who might be able to confirm. > > > > > > > > The proper workaround is to use a union: > > > > > > union { double (*cosine) (double); void *pointer; } u; > > > > > > u.pointer = dlsym(handle, "cos"); > > > ... > > > printf("%f\n", u.cosine(2.0)); > > > > This is seems much better, indeed. > > > > > > Have a lovely day! > > Alex > > > > > > > > Bruno > > > > > > > > > > > > > > > > -- > > <https://www.alejandro-colomar.es> ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: AW: clumsy cast in dlopen.3 2026-05-15 14:05 ` Martin Uecker @ 2026-05-15 15:15 ` Alejandro Colomar 2026-05-15 15:41 ` [PATCH v1] man/man3/dlopen.3: EXAMPLES: Simplify use of dlsym(3) Alejandro Colomar 1 sibling, 0 replies; 9+ messages in thread From: Alejandro Colomar @ 2026-05-15 15:15 UTC (permalink / raw) To: Martin Uecker; +Cc: Walter Harms, Bruno Haible, linux-man@vger.kernel.org [-- Attachment #1: Type: text/plain, Size: 3523 bytes --] Hi Martin, On 2026-05-15T16:05:24+0200, Martin Uecker wrote: > > There is no such thing needed here, you just do > > double (*cosine)(double); > > cosine = dlsym(handle, "cos"); Hmmmm, yes. I don't know why the manual page uses a cast in the POSIX version. The above wouldn't be enough in ISO C, since void* isn't guaranteed to work with function pointers. However, any systems where dlsym(3) works must support holding function pointers in void* (because otherwise, dlsym(3) itself wouldn't work), so ISO C shouldn't be a concern at all. Hmmm; I'll simplify the page. Thanks! Have a lovely day! Alex > > > Best, > Martin > > Am Freitag, dem 15.05.2026 um 11:56 +0200 schrieb Alejandro Colomar: > > Hi Walter, > > > > On 2026-05-15T08:35:49+0000, Walter Harms wrote: > > > Hello, > > > I agree the cast is not nice, (someone for a extension of C standard ?) > > > but i have to admit that i have never seen the trick with the union. > > > But it needs some explaination. The comment in the example is already huge, > > > i would ask for a comment subsektion for this behavier here. > > > > The thing about unions is that the only two ways for type punning that > > are blessed by ISO C are unions and memcpy(3). Everything else isn't > > allowed. > > > > Perfectly valid: > > > > static_assert(sizeof(int) == sizeof(float)); > > > > union u {int i; float f;}; > > > > float f; > > union u u; > > > > u.i = 42; > > f = u.f; > > > > Perfectly valid: > > > > static_assert(sizeof(int) == sizeof(float)); > > > > int i; > > float f; > > > > i = 42; > > memcpy(&f, &i, sizeof(float)); > > > > UB: > > > > static_assert(sizeof(int) == sizeof(float)); > > > > int i; > > float f; > > > > i = 42; > > f = *(float *) &i; > > > > > > Have a lovely day! > > Alex > > > > > btw: the original code in the example looks like this ... > > > cosine = (typeof(double (double)) *) dlsym(handle, "cos"); > > > > > > my2c > > > wh > > > > > > ________________________________________ > > > Von: Alejandro Colomar <alx@kernel.org> > > > Gesendet: Donnerstag, 14. Mai 2026 13:29:20 > > > An: Bruno Haible > > > Cc: linux-man@vger.kernel.org; Martin Uecker > > > Betreff: Re: clumsy cast in dlopen.3 > > > > > > Hi Bruno, > > > > > > On 2026-05-14T12:56:55+0200, Bruno Haible wrote: > > > > The dlopen.3 man page contains this text: > > > > > > > > *(void **) &cosine = dlsym(handle, "cos"); > > > > > > > > This (clumsy) cast conforms with the ISO C standard and will > > > > avoid any compiler warnings. > > > > > > > > However, such a cast violates the strict aliasing rules of ISO C, no? > > > > > > I think I agree. Dereferencing the pointer &cosine with a type > > > different than the type of the object is not allowed. I've CCed Martin, > > > who might be able to confirm. > > > > > > > > > > > The proper workaround is to use a union: > > > > > > > > union { double (*cosine) (double); void *pointer; } u; > > > > > > > > u.pointer = dlsym(handle, "cos"); > > > > ... > > > > printf("%f\n", u.cosine(2.0)); > > > > > > This is seems much better, indeed. > > > > > > > > > Have a lovely day! > > > Alex > > > > > > > > > > > Bruno > > > > > > > > > > > > > > > > > > > > > > -- > > > <https://www.alejandro-colomar.es> -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1] man/man3/dlopen.3: EXAMPLES: Simplify use of dlsym(3) 2026-05-15 14:05 ` Martin Uecker 2026-05-15 15:15 ` Alejandro Colomar @ 2026-05-15 15:41 ` Alejandro Colomar 2026-05-15 16:19 ` Bruno Haible 1 sibling, 1 reply; 9+ messages in thread From: Alejandro Colomar @ 2026-05-15 15:41 UTC (permalink / raw) To: linux-man; +Cc: Alejandro Colomar, Bruno Haible, Martin Uecker, Walter Harms The cast is entirely unnecessary. Conversion from/to void* and function pointers is implicit, and it's guaranteed by POSIX. ISO C is irrelevant here, because dlsym(3) requires POSIX, which provides the stronger guarantees that we need. And even before POSIX standardized these guarantees about void* and function pointers, and system implementing dlsym(3) would have to support them anyway, as otherwise dlsym(3) couldn't work at all. Reported-by: Bruno Haible <bruno@clisp.org> Suggested-by: Martin Uecker <uecker@tugraz.at> Cc: Walter Harms <wharms@bfs.de> Signed-off-by: Alejandro Colomar <alx@kernel.org> --- man/man3/dlopen.3 | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/man/man3/dlopen.3 b/man/man3/dlopen.3 index 482af099..d9be7502 100644 --- a/man/man3/dlopen.3 +++ b/man/man3/dlopen.3 @@ -567,23 +567,11 @@ .SS Program source \& dlerror(); /* Clear any existing error */ \& - cosine = (typeof(double (double)) *) dlsym(handle, "cos"); + cosine = dlsym(handle, "cos"); \& - /* According to the ISO C standard, casting between function - pointers and \[aq]void *\[aq], as done above, produces undefined results. - POSIX.1\-2001 and POSIX.1\-2008 accepted this state of affairs and - proposed the following workaround: -\& - *(void **) &cosine = dlsym(handle, "cos"); -\& - This (clumsy) cast conforms with the ISO C standard and will - avoid any compiler warnings. -\& - The 2013 Technical Corrigendum 1 to POSIX.1\-2008 improved matters - by requiring that conforming implementations support casting - \[aq]void *\[aq] to a function pointer. Nevertheless, some compilers - (e.g., gcc with the \[aq]\-pedantic\[aq] option) may complain about the - cast used in this program. */ + /* The 2013 Technical Corrigendum 1 to POSIX.1\-2008 + required that conforming implementations support + converting \[aq]void *\[aq] to a function pointer. */ .\" http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html#tag_03_112_08 .\" http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html#tag_16_96_07 .\" http://austingroupbugs.net/view.php?id=74 Range-diff against v0: -: -------- > 1: 508bb497 man/man3/dlopen.3: EXAMPLES: Simplify use of dlsym(3) -- 2.53.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v1] man/man3/dlopen.3: EXAMPLES: Simplify use of dlsym(3) 2026-05-15 15:41 ` [PATCH v1] man/man3/dlopen.3: EXAMPLES: Simplify use of dlsym(3) Alejandro Colomar @ 2026-05-15 16:19 ` Bruno Haible 2026-05-15 22:51 ` Alejandro Colomar 0 siblings, 1 reply; 9+ messages in thread From: Bruno Haible @ 2026-05-15 16:19 UTC (permalink / raw) To: linux-man, Alejandro Colomar; +Cc: Martin Uecker, Walter Harms The patch looks good to me. Thanks for removing the misleading comment! Bruno ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1] man/man3/dlopen.3: EXAMPLES: Simplify use of dlsym(3) 2026-05-15 16:19 ` Bruno Haible @ 2026-05-15 22:51 ` Alejandro Colomar 0 siblings, 0 replies; 9+ messages in thread From: Alejandro Colomar @ 2026-05-15 22:51 UTC (permalink / raw) To: Bruno Haible; +Cc: linux-man, Martin Uecker, Walter Harms [-- Attachment #1: Type: text/plain, Size: 336 bytes --] Hi Bruno, On 2026-05-15T18:19:44+0200, Bruno Haible wrote: > The patch looks good to me. Thanks for removing the misleading comment! You're welcome! Thanks for the report! I've taken your reply as an Acked-by tag in the patch. Have a lovely night! Alex > Bruno > > > -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-05-15 22:51 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-14 10:56 clumsy cast in dlopen.3 Bruno Haible 2026-05-14 11:29 ` Alejandro Colomar 2026-05-15 8:35 ` AW: " Walter Harms 2026-05-15 9:56 ` Alejandro Colomar 2026-05-15 14:05 ` Martin Uecker 2026-05-15 15:15 ` Alejandro Colomar 2026-05-15 15:41 ` [PATCH v1] man/man3/dlopen.3: EXAMPLES: Simplify use of dlsym(3) Alejandro Colomar 2026-05-15 16:19 ` Bruno Haible 2026-05-15 22:51 ` Alejandro Colomar
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.