[RFC] Prevent tailcall optimizations of libdl functions

classic Classic list List threaded Threaded
30 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[RFC] Prevent tailcall optimizations of libdl functions

Yuri Gribov
Hi all,

This is a ping on https://sourceware.org/bugzilla/show_bug.cgi?id=21050

Some libdl functions rely on return address to figure out the calling
DSO and then use this information in computation (e.g. output of dlsym
depends on which library called it).

As reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66826 this
may break under tailcall optimization i.e. in cases like

  return dlsym(...);

Rich Felker suggested that adding new GCC attribute is a possible
solution. Another option would be to hack around dlsym to prevent
tailcall from happening e.g.
  #define dlsym(h, name) { volatile void *sym = dlsym(h, name); return
(void *)sym; }

Which solution is more appropriate for Glibc?

-Yury
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Florian Weimer-5
On 01/25/2017 09:12 AM, Yuri Gribov wrote:

> Hi all,
>
> This is a ping on https://sourceware.org/bugzilla/show_bug.cgi?id=21050
>
> Some libdl functions rely on return address to figure out the calling
> DSO and then use this information in computation (e.g. output of dlsym
> depends on which library called it).
>
> As reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66826 this
> may break under tailcall optimization i.e. in cases like
>
>   return dlsym(...);
>
> Rich Felker suggested that adding new GCC attribute is a possible
> solution.

Several functions have essentially the same issue, so this seems a
reasonable approach.

> Another option would be to hack around dlsym to prevent
> tailcall from happening e.g.
>   #define dlsym(h, name) { volatile void *sym = dlsym(h, name); return
> (void *)sym; }

I'm not convinced that this prevents a tail call in all cases.  I'd also
caution against adding yet another mechanism to preserve the caller context.

If we cannot get the GCC attribute to work, we should move dlsym into
libc_nonshared.a and use __dso_handle, like we do for other functions
which require the caller context.  This is not the direction I want us
to move in; I prefer __builtin_return_address because it is easier to
maintain, but that has the problem with tail calls.

Thanks,
Florian
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Rich Felker-3
On Wed, Jan 25, 2017 at 12:28:41PM +0100, Florian Weimer wrote:

> On 01/25/2017 09:12 AM, Yuri Gribov wrote:
> >Hi all,
> >
> >This is a ping on https://sourceware.org/bugzilla/show_bug.cgi?id=21050
> >
> >Some libdl functions rely on return address to figure out the calling
> >DSO and then use this information in computation (e.g. output of dlsym
> >depends on which library called it).
> >
> >As reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66826 this
> >may break under tailcall optimization i.e. in cases like
> >
> >  return dlsym(...);
> >
> >Rich Felker suggested that adding new GCC attribute is a possible
> >solution.
>
> Several functions have essentially the same issue, so this seems a
> reasonable approach.
>
> >Another option would be to hack around dlsym to prevent
> >tailcall from happening e.g.
> >  #define dlsym(h, name) { volatile void *sym = dlsym(h, name); return
> >(void *)sym; }
>
> I'm not convinced that this prevents a tail call in all cases.  I'd
> also caution against adding yet another mechanism to preserve the
> caller context.
>
> If we cannot get the GCC attribute to work, we should move dlsym
> into libc_nonshared.a and use __dso_handle, like we do for other
> functions which require the caller context.  This is not the
> direction I want us to move in; I prefer __builtin_return_address
> because it is easier to maintain, but that has the problem with tail
> calls.

FWIW this technique is non-conforming, at least for any standard
functions it's used on, since it breaks pointer equality. A conforming
program can evaluate p1==p2, where p1=dlsym is assigned in one dso and
p2=dlsym is assigned in another, and must see equality on a conforming
implementation. As such I think this hack needs to be removed from
other functions like stat.

Rich
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Florian Weimer-5
On 01/25/2017 03:08 PM, Rich Felker wrote:

> FWIW this technique is non-conforming, at least for any standard
> functions it's used on, since it breaks pointer equality. A conforming
> program can evaluate p1==p2, where p1=dlsym is assigned in one dso and
> p2=dlsym is assigned in another, and must see equality on a conforming
> implementation. As such I think this hack needs to be removed from
> other functions like stat.

Is there a specific requirement in POSIX to that effect, or is it an
accident as the result of how POSIX and ISO C interact?

As far as I can tell, ISO C specifies function pointer equality by
saying that pointers compare equal iff they refer to the “same […]
function”, but the standard does not seem to define what makes two
functions the same.

(But even if it is fully conforming or acceptable for other reasons, I
dislike the __dso_handle technique because it is too complex.)

Thanks,
Florian

Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Joseph Myers
In reply to this post by Rich Felker-3
On Wed, 25 Jan 2017, Rich Felker wrote:

> FWIW this technique is non-conforming, at least for any standard
> functions it's used on, since it breaks pointer equality. A conforming
> program can evaluate p1==p2, where p1=dlsym is assigned in one dso and
> p2=dlsym is assigned in another, and must see equality on a conforming
> implementation. As such I think this hack needs to be removed from
> other functions like stat.

A conforming program does not use shared libraries other than those
provided by the system and POSIX does not define any way to build shared
libraries.  If shared libraries are supported as an extension, ISO C and
POSIX impose no requirements on how symbol resolution semantics when that
feature is used might differ from symbol resolution semantics when only
standard features are used.

(I put stat in the category of "do this differently if we move to
libc.so.7", i.e. replace the very old versioning mechanism by normal
symbol versioning if making such an (unlikely) global ABI transition.)

--
Joseph S. Myers
[hidden email]
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Yuri Gribov
On Wed, Jan 25, 2017 at 2:34 PM, Joseph Myers <[hidden email]> wrote:

> On Wed, 25 Jan 2017, Rich Felker wrote:
>
>> FWIW this technique is non-conforming, at least for any standard
>> functions it's used on, since it breaks pointer equality. A conforming
>> program can evaluate p1==p2, where p1=dlsym is assigned in one dso and
>> p2=dlsym is assigned in another, and must see equality on a conforming
>> implementation. As such I think this hack needs to be removed from
>> other functions like stat.
>
> A conforming program does not use shared libraries other than those
> provided by the system and POSIX does not define any way to build shared
> libraries.  If shared libraries are supported as an extension, ISO C and
> POSIX impose no requirements on how symbol resolution semantics when that
> feature is used might differ from symbol resolution semantics when only
> standard features are used.
>
> (I put stat in the category of "do this differently if we move to
> libc.so.7", i.e. replace the very old versioning mechanism by normal
> symbol versioning if making such an (unlikely) global ABI transition.)

FWIW it sounds like GCC attribute would be the most natural solution
(and probably also useful in other contexts). I'll try to cook a patch
for GCC if there are no objections.

-I
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Szabolcs Nagy-2
On 25/01/17 15:32, Yuri Gribov wrote:
> FWIW it sounds like GCC attribute would be the most natural solution
> (and probably also useful in other contexts). I'll try to cook a patch
> for GCC if there are no objections.

note that even if dlsym is marked notailcall, with

p = dlsym;
...
return p();

if the type of p does not carry the attributes of
dlsym then this can be a tailcall.

Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Florian Weimer-5
On 01/25/2017 04:38 PM, Szabolcs Nagy wrote:

> On 25/01/17 15:32, Yuri Gribov wrote:
>> FWIW it sounds like GCC attribute would be the most natural solution
>> (and probably also useful in other contexts). I'll try to cook a patch
>> for GCC if there are no objections.
>
> note that even if dlsym is marked notailcall, with
>
> p = dlsym;
> ...
> return p();
>
> if the type of p does not carry the attributes of
> dlsym then this can be a tailcall.

Yes, but dlsym would still see the address of the function containing
the dlsym call, which is what we need to determine the relevant object.

Thanks,
Florian

Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Szabolcs Nagy-2
On 25/01/17 15:40, Florian Weimer wrote:

> On 01/25/2017 04:38 PM, Szabolcs Nagy wrote:
>> On 25/01/17 15:32, Yuri Gribov wrote:
>>> FWIW it sounds like GCC attribute would be the most natural solution
>>> (and probably also useful in other contexts). I'll try to cook a patch
>>> for GCC if there are no objections.
>>
>> note that even if dlsym is marked notailcall, with
>>
>> p = dlsym;
>> ...
>> return p();
>>
>> if the type of p does not carry the attributes of
>> dlsym then this can be a tailcall.
>
> Yes, but dlsym would still see the address of the function containing the dlsym call, which is what we need to
> determine the relevant object.
>

how?

Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Jeff Law
In reply to this post by Florian Weimer-5
On 01/25/2017 07:32 AM, Florian Weimer wrote:

> On 01/25/2017 03:08 PM, Rich Felker wrote:
>
>> FWIW this technique is non-conforming, at least for any standard
>> functions it's used on, since it breaks pointer equality. A conforming
>> program can evaluate p1==p2, where p1=dlsym is assigned in one dso and
>> p2=dlsym is assigned in another, and must see equality on a conforming
>> implementation. As such I think this hack needs to be removed from
>> other functions like stat.
>
> Is there a specific requirement in POSIX to that effect, or is it an
> accident as the result of how POSIX and ISO C interact?
>
> As far as I can tell, ISO C specifies function pointer equality by
> saying that pointers compare equal iff they refer to the “same […]
> function”, but the standard does not seem to define what makes two
> functions the same.
>
> (But even if it is fully conforming or acceptable for other reasons, I
> dislike the __dso_handle technique because it is too complex.)
I've always interpreted it as "if I dereference the function pointers,
do I get into the same function".  It's not proper standards language,
but you get the basic idea.

The 32bit HPUX runtime had fptr descriptors which were not unique and
were only used for a subset of indirect calls.  So you couldn't just
compare function pointers.  You can do call into a special routine to
compute/extract the actual address for comparison purposes.

Jeff
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Florian Weimer-5
In reply to this post by Szabolcs Nagy-2
On 01/25/2017 04:41 PM, Szabolcs Nagy wrote:

> On 25/01/17 15:40, Florian Weimer wrote:
>> On 01/25/2017 04:38 PM, Szabolcs Nagy wrote:
>>> On 25/01/17 15:32, Yuri Gribov wrote:
>>>> FWIW it sounds like GCC attribute would be the most natural solution
>>>> (and probably also useful in other contexts). I'll try to cook a patch
>>>> for GCC if there are no objections.
>>>
>>> note that even if dlsym is marked notailcall, with
>>>
>>> p = dlsym;
>>> ...
>>> return p();
>>>
>>> if the type of p does not carry the attributes of
>>> dlsym then this can be a tailcall.
>>
>> Yes, but dlsym would still see the address of the function containing the dlsym call, which is what we need to
>> determine the relevant object.
>
> how?

At worst, the return address points to the code which jumps to the
address p.  This code is still in the object which calls dlsym.

Florian

Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Jakub Jelinek
On Wed, Jan 25, 2017 at 04:43:32PM +0100, Florian Weimer wrote:

> On 01/25/2017 04:41 PM, Szabolcs Nagy wrote:
> > On 25/01/17 15:40, Florian Weimer wrote:
> > > On 01/25/2017 04:38 PM, Szabolcs Nagy wrote:
> > > > On 25/01/17 15:32, Yuri Gribov wrote:
> > > > > FWIW it sounds like GCC attribute would be the most natural solution
> > > > > (and probably also useful in other contexts). I'll try to cook a patch
> > > > > for GCC if there are no objections.
> > > >
> > > > note that even if dlsym is marked notailcall, with
> > > >
> > > > p = dlsym;
> > > > ...
> > > > return p();
> > > >
> > > > if the type of p does not carry the attributes of
> > > > dlsym then this can be a tailcall.
> > >
> > > Yes, but dlsym would still see the address of the function containing the dlsym call, which is what we need to
> > > determine the relevant object.
> >
> > how?
>
> At worst, the return address points to the code which jumps to the address
> p.  This code is still in the object which calls dlsym.

That can be a tail call and you get exactly the same problem as with direct
calls to dlsym.  We can make no_tail_call attribute a function type
attribute (like e.g. warn_unused_result and various others), then
you can actually avoid tail calls even on indirect calls.
But if you just
  void (*p) (void *, const char *) = dlsym;
  asm ("" : "+r" (p));
  return p (handle, "foobar");
then it can still be tail called (as the optimizers can't turn
that into a direct call and the function pointer doesn't have that
attribute).  And you can run into stuff like PR71463 too.

        Jakub
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Szabolcs Nagy-2
In reply to this post by Florian Weimer-5
On 25/01/17 15:43, Florian Weimer wrote:

> On 01/25/2017 04:41 PM, Szabolcs Nagy wrote:
>> On 25/01/17 15:40, Florian Weimer wrote:
>>> On 01/25/2017 04:38 PM, Szabolcs Nagy wrote:
>>>> On 25/01/17 15:32, Yuri Gribov wrote:
>>>>> FWIW it sounds like GCC attribute would be the most natural solution
>>>>> (and probably also useful in other contexts). I'll try to cook a patch
>>>>> for GCC if there are no objections.
>>>>
>>>> note that even if dlsym is marked notailcall, with
>>>>
>>>> p = dlsym;
>>>> ...
>>>> return p();
>>>>
>>>> if the type of p does not carry the attributes of
>>>> dlsym then this can be a tailcall.
>>>
>>> Yes, but dlsym would still see the address of the function containing the dlsym call, which is what we need to
>>> determine the relevant object.
>>
>> how?
>
> At worst, the return address points to the code which jumps to the address p.  This code is still in the object
> which calls dlsym.
>

i don't immediately see why.

i'd assume if we want f(RTLD_NEXT, sym) work
for a function pointer f pointing to dlsym
then it would need to prevent tco just like
dlsym to have a return address in the right dso.

(e.g. g() in dso1 calls h() in dso2 which
calls f that is dlsym, whether h tailcalls
f or not seem to matter)

Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Florian Weimer-5
In reply to this post by Jakub Jelinek
On 01/25/2017 04:50 PM, Jakub Jelinek wrote:

> On Wed, Jan 25, 2017 at 04:43:32PM +0100, Florian Weimer wrote:
>> On 01/25/2017 04:41 PM, Szabolcs Nagy wrote:
>>> On 25/01/17 15:40, Florian Weimer wrote:
>>>> On 01/25/2017 04:38 PM, Szabolcs Nagy wrote:
>>>>> On 25/01/17 15:32, Yuri Gribov wrote:
>>>>>> FWIW it sounds like GCC attribute would be the most natural solution
>>>>>> (and probably also useful in other contexts). I'll try to cook a patch
>>>>>> for GCC if there are no objections.
>>>>>
>>>>> note that even if dlsym is marked notailcall, with
>>>>>
>>>>> p = dlsym;
>>>>> ...
>>>>> return p();
>>>>>
>>>>> if the type of p does not carry the attributes of
>>>>> dlsym then this can be a tailcall.
>>>>
>>>> Yes, but dlsym would still see the address of the function containing the dlsym call, which is what we need to
>>>> determine the relevant object.
>>>
>>> how?
>>
>> At worst, the return address points to the code which jumps to the address
>> p.  This code is still in the object which calls dlsym.
>
> That can be a tail call and you get exactly the same problem as with direct
> calls to dlsym.

Sorry, I don't see how.  On x86_64, we might end up with this
instruction sequence:

   call dlsym
   jmp %rax

But this means that the call to dlsym is not a tail call, and
__builtin_return_address in dlsym will return the address of the jmp
instruction.

A tail call has to be in a tail position.  If there is another function
call after it, it is no longer in a tail position.

What am I missing?

Thanks,
Florian
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Szabolcs Nagy-2
On 25/01/17 15:56, Florian Weimer wrote:

> On 01/25/2017 04:50 PM, Jakub Jelinek wrote:
>> On Wed, Jan 25, 2017 at 04:43:32PM +0100, Florian Weimer wrote:
>>> On 01/25/2017 04:41 PM, Szabolcs Nagy wrote:
>>>> On 25/01/17 15:40, Florian Weimer wrote:
>>>>> On 01/25/2017 04:38 PM, Szabolcs Nagy wrote:
>>>>>> On 25/01/17 15:32, Yuri Gribov wrote:
>>>>>>> FWIW it sounds like GCC attribute would be the most natural solution
>>>>>>> (and probably also useful in other contexts). I'll try to cook a patch
>>>>>>> for GCC if there are no objections.
>>>>>>
>>>>>> note that even if dlsym is marked notailcall, with
>>>>>>
>>>>>> p = dlsym;
>>>>>> ...
>>>>>> return p();
>>>>>>
>>>>>> if the type of p does not carry the attributes of
>>>>>> dlsym then this can be a tailcall.
>>>>>
>>>>> Yes, but dlsym would still see the address of the function containing the dlsym call, which is what we
>>>>> need to
>>>>> determine the relevant object.
>>>>
>>>> how?
>>>
>>> At worst, the return address points to the code which jumps to the address
>>> p.  This code is still in the object which calls dlsym.
>>
>> That can be a tail call and you get exactly the same problem as with direct
>> calls to dlsym.
>
> Sorry, I don't see how.  On x86_64, we might end up with this instruction sequence:
>
>   call dlsym
>   jmp %rax
>
> But this means that the call to dlsym is not a tail call, and __builtin_return_address in dlsym will return the
> address of the jmp instruction.
>
> A tail call has to be in a tail position.  If there is another function call after it, it is no longer in a
> tail position.
>
> What am I missing?
>

it's not p=dlsym(); but p=dlsym;

Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Florian Weimer-5
On 01/25/2017 04:57 PM, Szabolcs Nagy wrote:

> it's not p=dlsym(); but p=dlsym;

Yeah, right.  That's what I was missing.

I think the best we can do in this case is to preserve the attribute in
the function pointer (if __typeof__ is used).

Thanks,
Florian
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Rich Felker-3
In reply to this post by Joseph Myers
On Wed, Jan 25, 2017 at 02:34:32PM +0000, Joseph Myers wrote:

> On Wed, 25 Jan 2017, Rich Felker wrote:
>
> > FWIW this technique is non-conforming, at least for any standard
> > functions it's used on, since it breaks pointer equality. A conforming
> > program can evaluate p1==p2, where p1=dlsym is assigned in one dso and
> > p2=dlsym is assigned in another, and must see equality on a conforming
> > implementation. As such I think this hack needs to be removed from
> > other functions like stat.
>
> A conforming program does not use shared libraries other than those
> provided by the system and POSIX does not define any way to build shared
> libraries.  If shared libraries are supported as an extension, ISO C and
> POSIX impose no requirements on how symbol resolution semantics when that
> feature is used might differ from symbol resolution semantics when only
> standard features are used.

While this might be technically defensible, it's nonsensical in
relation to actual practice, especially in the historical context
where the GNU tools have treated static-linking/static-libraries as
deprecated or at best second-class citizens. GNU libtool even makes it
impossible to static-link except for libraries being built in-tree as
part of the same package. As such, from the standpoint of a complete
GNU system using GNU tools, dynamic linking all libraries is the de
facto default, and for them not to have the semantics the C language
defines is a bug.

> (I put stat in the category of "do this differently if we move to
> libc.so.7", i.e. replace the very old versioning mechanism by normal
> symbol versioning if making such an (unlikely) global ABI transition.)

I don't see any reason it couldn't be done in libc.so.6, still having
the old xstat etc. symbols for compatibility but removing stat etc.
from libc_nonshared.a and adding them to libc.so.6.

Rich
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Rich Felker-3
In reply to this post by Jeff Law
On Wed, Jan 25, 2017 at 08:42:44AM -0700, Jeff Law wrote:

> On 01/25/2017 07:32 AM, Florian Weimer wrote:
> >On 01/25/2017 03:08 PM, Rich Felker wrote:
> >
> >>FWIW this technique is non-conforming, at least for any standard
> >>functions it's used on, since it breaks pointer equality. A conforming
> >>program can evaluate p1==p2, where p1=dlsym is assigned in one dso and
> >>p2=dlsym is assigned in another, and must see equality on a conforming
> >>implementation. As such I think this hack needs to be removed from
> >>other functions like stat.
> >
> >Is there a specific requirement in POSIX to that effect, or is it an
> >accident as the result of how POSIX and ISO C interact?
> >
> >As far as I can tell, ISO C specifies function pointer equality by
> >saying that pointers compare equal iff they refer to the “same […]
> >function”, but the standard does not seem to define what makes two
> >functions the same.
> >
> >(But even if it is fully conforming or acceptable for other reasons, I
> >dislike the __dso_handle technique because it is too complex.)
> I've always interpreted it as "if I dereference the function
> pointers, do I get into the same function".  It's not proper
> standards language, but you get the basic idea.
>
> The 32bit HPUX runtime had fptr descriptors which were not unique
> and were only used for a subset of indirect calls.  So you couldn't
> just compare function pointers.  You can do call into a special
> routine to compute/extract the actual address for comparison
> purposes.

That's not a conforming C implementation. C specifies working
comparison of function pointers.

Rich
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Rich Felker-3
In reply to this post by Florian Weimer-5
On Wed, Jan 25, 2017 at 04:59:29PM +0100, Florian Weimer wrote:
> On 01/25/2017 04:57 PM, Szabolcs Nagy wrote:
>
> >it's not p=dlsym(); but p=dlsym;
>
> Yeah, right.  That's what I was missing.
>
> I think the best we can do in this case is to preserve the attribute
> in the function pointer (if __typeof__ is used).

Obviously portable code declaring a pointer to dlsym is going to use
the documented signature, not __typeof__ or a custom attribute.

Perhaps a better solution than these hacks it just to specify that
RTLD_NEXT has undefined behavior if dlsym is called via a function
pointer expression which is not a constant expression. (Technically,
under C99 and later, in normal call dlsym(...), the () operator is
applied to a function pointer -- the one dlsym decays to -- so you
can't just say using function pointers is undefined.)

Rich
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Prevent tailcall optimizations of libdl functions

Jeff Law
In reply to this post by Rich Felker-3
On 01/25/2017 09:54 AM, Rich Felker wrote:

> On Wed, Jan 25, 2017 at 08:42:44AM -0700, Jeff Law wrote:
>> On 01/25/2017 07:32 AM, Florian Weimer wrote:
>>> On 01/25/2017 03:08 PM, Rich Felker wrote:
>>>
>>>> FWIW this technique is non-conforming, at least for any standard
>>>> functions it's used on, since it breaks pointer equality. A conforming
>>>> program can evaluate p1==p2, where p1=dlsym is assigned in one dso and
>>>> p2=dlsym is assigned in another, and must see equality on a conforming
>>>> implementation. As such I think this hack needs to be removed from
>>>> other functions like stat.
>>>
>>> Is there a specific requirement in POSIX to that effect, or is it an
>>> accident as the result of how POSIX and ISO C interact?
>>>
>>> As far as I can tell, ISO C specifies function pointer equality by
>>> saying that pointers compare equal iff they refer to the “same […]
>>> function”, but the standard does not seem to define what makes two
>>> functions the same.
>>>
>>> (But even if it is fully conforming or acceptable for other reasons, I
>>> dislike the __dso_handle technique because it is too complex.)
>> I've always interpreted it as "if I dereference the function
>> pointers, do I get into the same function".  It's not proper
>> standards language, but you get the basic idea.
>>
>> The 32bit HPUX runtime had fptr descriptors which were not unique
>> and were only used for a subset of indirect calls.  So you couldn't
>> just compare function pointers.  You can do call into a special
>> routine to compute/extract the actual address for comparison
>> purposes.
>
> That's not a conforming C implementation. C specifies working
> comparison of function pointers.
This was all hidden by the compiler.  At the C level you just compared
the function pointers.

jeff
12