Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #384092

Re: Casting the return value of ...

From Tim Rentsch <tr.17687@z991.linuxsc.com>
Newsgroups comp.lang.c
Subject Re: Casting the return value of ...
Date 2024-03-29 15:52 -0700
Organization A noiseless patient Spider
Message-ID <8634s8k5wp.fsf@linuxsc.com> (permalink)
References <uu416t$33u55$1@news.xmission.com>

Show all headers | View raw


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

Back to comp.lang.c | Previous | NextPrevious in thread | Find similar


Thread

Casting the return value of ... gazelle@shell.xmission.com (Kenny McCormack) - 2024-03-28 15:09 +0000
  Re: Casting the return value of ... Kaz Kylheku <433-929-6894@kylheku.com> - 2024-03-28 18:16 +0000
    Re: Casting the return value of ... scott@slp53.sl.home (Scott Lurndal) - 2024-03-28 18:53 +0000
      Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-03-30 10:33 -0700
        Re: Casting the return value of ... scott@slp53.sl.home (Scott Lurndal) - 2024-03-30 19:29 +0000
          Re: Casting the return value of ... Lawrence D'Oliveiro <ldo@nz.invalid> - 2024-03-30 23:05 +0000
            Re: Casting the return value of ... scott@slp53.sl.home (Scott Lurndal) - 2024-03-30 23:25 +0000
            Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-03-31 15:44 +0200
            Re: Casting the return value of ... "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2024-03-31 13:15 -0700
          Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-04-08 23:01 -0700
            Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-04-09 10:03 +0200
    Re: Casting the return value of ... Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2024-03-28 12:38 -0700
      Re: Casting the return value of ... bart <bc@freeuk.com> - 2024-03-28 20:30 +0000
        Re: Casting the return value of ... Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2024-03-28 14:07 -0700
          Re: Casting the return value of ... "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2024-03-28 14:15 -0700
          Re: Casting the return value of ... Kaz Kylheku <433-929-6894@kylheku.com> - 2024-03-28 21:44 +0000
            Re: Casting the return value of ... Kaz Kylheku <433-929-6894@kylheku.com> - 2024-03-28 22:01 +0000
              Re: Casting the return value of ... Kaz Kylheku <433-929-6894@kylheku.com> - 2024-03-28 22:33 +0000
                Re: Casting the return value of ... Michael S <already5chosen@yahoo.com> - 2024-03-29 15:53 +0200
                gcc Bugzilla search (was: Casting the return value of ...) Michael S <already5chosen@yahoo.com> - 2024-03-29 16:01 +0200
                Re: gcc Bugzilla search David Brown <david.brown@hesbynett.no> - 2024-03-29 17:00 +0100
            Re: Casting the return value of ... Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2024-03-28 15:37 -0700
          Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-03-29 14:06 +0100
            Re: Casting the return value of ... "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2024-03-29 15:46 -0700
        Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-03-29 13:58 +0100
          Re: Casting the return value of ... bart <bc@freeuk.com> - 2024-03-29 13:32 +0000
            Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-03-29 17:10 +0100
            Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-03-30 02:32 -0700
              Re: Casting the return value of ... bart <bc@freeuk.com> - 2024-03-30 11:14 +0000
                Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-04-08 23:41 -0700
  Re: Casting the return value of ... Andrey Tarasevich <andreytarasevich@hotmail.com> - 2024-03-28 21:41 -0700
    Re: Casting the return value of ... Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2024-03-28 22:02 -0700
  Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-03-29 15:52 -0700

csiph-web