All of lore.kernel.org
 help / color / mirror / Atom feed
* 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.