Email List: Xaustin-group-lX
[All Lists]

Re: Return type of dlsym

To: "Marc Aurele La France" <yyy@xxxxxxxxxxx>, "Matt Seitz" <yyyyyy@xxxxxxxxx>
Subject: Re: Return type of dlsym
From: "Wojtek Lerch" <yyyyyy@xxxxxxx>
Date: Sat, 13 Apr 2002 02:32:50 -0000
Cc: <yyyyyyyyyyyyyy@xxxxxxxxxxxxx>
Marc Aurele La France <yyy@xxxxxxxxxxx> said:
> On Fri, 12 Apr 2002, Matt Seitz wrote:
> > Any suggestions for improving this idea?

The reason the C standard makes this undefined is because data pointers and 
function pointers may have different sizes on some platforms.  If you pick 
either one for the return type of dlsym(), converting to the other kind of 
pointers will lose some significant bits on some platforms.  If you want to 
make this work on all such platforms, you must make the return type of dlsym
() implementation-defined, and require a typecast.

Of course, you can instead say that you don't care about platforms that have 
data pointers smaller than function pointers; dlsym(), as currently defined, 
has no chance of working on such platforms anyway.

> Oddly enough, I recently ran into this in my own work.  What I ended up
> with is instead of
> 
>       fptr = (int (*)(int))dlsym(handle, "my_function");
>
> I did
> 
>       *(void **)(&fptr) = dlsym(handle, "my_function");
> 
> ... which is, I'll grant, a little kludgy, but is perfectly legal in
> ANSI or ISO C terms.

A little?

It's only "legal" in the sense that it doesn't require the compiler to issue 
a diagnostic; but it is undefined behaviour in ISO C.  And it's actually less 
portable than the original typecast:

  * On a platform where function pointers are smaller than data pointers, 
you're clobbering memory outside of the fptr variable.  A cast from void* to 
a function pointer would just work: yes, it would throw away the extra bits 
instead of storing them in some unrelated variable, but if the symbol you 
asked for indeed was a function, those extra bits would have all been 
insignificant anyway.

 * Even if function pointers are the same size as data pointers, their 
representation could be different.  Imagine a machine that stores function 
pointers as "big endian" (segment, then offset) but data pointers as "little 
endian" (offset, then segment).  A normal typecast would allow the compiler 
to swap the segment and the offset; yours doesn't.

<Prev in Thread] Current Thread [Next in Thread>