Re: Casting the return value of ...

Liste des GroupesRevenir à l c 
Sujet : Re: Casting the return value of ...
De : tr.17687 (at) *nospam* z991.linuxsc.com (Tim Rentsch)
Groupes : comp.lang.c
Date : 30. Mar 2024, 00:52:06
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <8634s8k5wp.fsf@linuxsc.com>
References : 1
User-Agent : Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
gazelle@shell.xmission.com (Kenny McCormack) writes:

[some white space added or deleted]

I think this is a variation on that old CLC standard "Why you should not
cast the return value of malloc()".
>
Caution:  POSIX (non-strict ISO) stuff coming up.  If this bothers you,
please hit "next" right now.
>
I frequently write "interposer" functions as shared libraries (on Linux).
Generally, this requires using dlsym() and RTLD_NEXT to get a pointer to the
"real" function, so that you can call that as part of your interposer
routine.  I have always done it like this (e.g., for a function returning
char *, taking 2 size_t args - just to pick an arbitrary example to make
things more concrete):
>
char *someFunction(size_t,size_t) {
    static char * (*real_someFunction) (size_t,size_t);
>
    if (!real_someFunction)
       real_someFunction =
            (char * (*real_someFunction) (size_t,size_t))
                 dlsym(RTLD_NEXT,"someFunction");
...
    }

Presumably you meant (char * (*)(size_t,size_t)) for the type used
in the cast.

This works fine (and compiles clean with the usual -W -Wall -Werror).

Did you also try with -pedantic or -pedantic-errors?  If not then
it's a good idea to include it.  Even if you don't use -pedantic all
the time, it's a good idea to include it occasionally, especially in
cases like this where you want to understand more about what is
going on.


But here's the thing.  Is the casting of the result of dlsym() necessary?
Isn't this the same as "casting the return value of malloc()", where you
don't need to cast it since it auto-magically gets casted by being assigned
to the thing on the left of the assignment?

There are a couple of reasons why this doesn't work, and also why
it isn't a good idea.  More explanation below.

Note that it is duplicative, having to specify the type info for the
function pointer twice - once in the declaration of the pointer and
then again in the dlsym() call.  It'd be better (in terms of
maintenance) if you only had to do it once.

Certainly it is inconvenient to give a long and complicated type (or
type name) multiple times.  Typically most of the inconvenience is
avoided by using a typedef, as for example

    typedef char *SomeF( size_t, size_t );
    static  SomeF *f_pointer;
    ...
    f_pointer = (SomeF *)( ... );

I should add that this construction doesn't help in the dlsym()
situation, but it illustrates the principle of using typedef.


But here's where it gets interesting.  In the man page for dlopen(), we
find this example code and a long detailed comment:
>
     double (*cosine)(double);
...
  cosine = (double (*)(double)) dlsym(handle, "cos");
>
     /* According to the ISO C standard, casting between function
        pointers and 'void *', as done above, produces undefined results.
        POSIX.1-2003 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 to POSIX.1-2008 (a.k.a.
        POSIX.1-2013) improved matters by requiring that conforming
        implementations support casting 'void *' to a function pointer.
        Nevertheless, some compilers (e.g., gcc with the '-pedantic'
        option) may complain about the cast used in this program. */
>
So, they seem to think the cast is necessary - or at least a good idea,
Are they right?

They are right in the important sense that using a straightforward
cast is the wrong way to tackle this problem.  The "solution" given
above is ill advised because it strays into the realm of undefined
behavior.  But the key point is correct.  A fix for how to address
the problem is given below.

And why do we even need the "clumsy" cast?  Why not just:
>
        cosine = dlsym(handle, "cos");

The C standard does not consider function pointers and object
pointers to be inter-convertible.  Because of that, there is no
reason to allow a void * pointer to be assigned to a variable
that has a function pointer type.

Returning to your original scenario, here is a way to do what you
want that stays inside the ISO C limits, and so avoids the problem
mentioned in the dlopen() man page:

/* presume there is a declaration for dlsym() available */

char *
outerFunction( size_t a, size_t b ){
  typedef  char  *SF_f( size_t, size_t );  // an actual function type
  extern   SF_f   outerFunction;           // verify type compatibility
  static   SF_f  *dynamic_f;               // pointer to dynamically loaded f

    if(  ! dynamic_f  ){
        union { void *v; SF_f *f; } it = { dlsym( 0, "someFunction" ) };
        dynamic_f = it.f;
        // we might want to check that dynamic_f is not null now
    }
    return  dynamic_f( a, b );
}

This code compiles cleanly as C99 or C11, under both gcc and clang,
with a full set of restrictive diagnostics:  -Wall -Wextra -Werror
and -pedantic-errors.  (A simple change will allow it to compile,
and compile cleanly, as C90 if that is desired.)

Date Sujet#  Auteur
28 Mar 24 * Casting the return value of ...31Kenny McCormack
28 Mar 24 +* Re: Casting the return value of ...27Kaz Kylheku
28 Mar 24 i+* Re: Casting the return value of ...20Keith Thompson
28 Mar 24 ii`* Re: Casting the return value of ...19bart
28 Mar 24 ii +* Re: Casting the return value of ...12Keith Thompson
28 Mar 24 ii i+- Re: Casting the return value of ...1Chris M. Thomasson
28 Mar 24 ii i+* Re: Casting the return value of ...8Kaz Kylheku
29 Mar 24 ii ii+* Re: Casting the return value of ...5Kaz Kylheku
29 Mar 24 ii iii`* Re: Casting the return value of ...4Kaz Kylheku
29 Mar 24 ii iii `* Re: Casting the return value of ...3Michael S
29 Mar 24 ii iii  `* gcc Bugzilla search (was: Casting the return value of ...)2Michael S
29 Mar 24 ii iii   `- Re: gcc Bugzilla search1David Brown
29 Mar 24 ii ii+- Re: Casting the return value of ...1Keith Thompson
8 Jun 24 ii ii`- Re: Casting the return value of ...1Tim Rentsch
29 Mar 24 ii i`* Re: Casting the return value of ...2David Brown
30 Mar 24 ii i `- Re: Casting the return value of ...1Chris M. Thomasson
29 Mar 24 ii `* Re: Casting the return value of ...6David Brown
29 Mar 24 ii  `* Re: Casting the return value of ...5bart
29 Mar 24 ii   +- Re: Casting the return value of ...1David Brown
30 Mar 24 ii   `* Re: Casting the return value of ...3Tim Rentsch
30 Mar 24 ii    `* Re: Casting the return value of ...2bart
9 Apr 24 ii     `- Re: Casting the return value of ...1Tim Rentsch
30 Mar 24 i`* Re: Casting the return value of ...6Tim Rentsch
31 Mar 24 i +* Re: Casting the return value of ...3Lawrence D'Oliveiro
31 Mar 24 i i+- Re: Casting the return value of ...1David Brown
31 Mar 24 i i`- Re: Casting the return value of ...1Chris M. Thomasson
9 Apr 24 i `* Re: Casting the return value of ...2Tim Rentsch
9 Apr 24 i  `- Re: Casting the return value of ...1David Brown
29 Mar 24 +* Re: Casting the return value of ...2Andrey Tarasevich
29 Mar 24 i`- Re: Casting the return value of ...1Keith Thompson
30 Mar 24 `- Re: Casting the return value of ...1Tim Rentsch

Haut de la page

Les messages affichés proviennent d'usenet.

NewsPortal