* 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.