Git Product home page Git Product logo

Comments (2)

vvaltchev avatar vvaltchev commented on May 17, 2024

Hi Petar,
thanks for the detailed research.
Overall, it makes sense to me, even if I'm far from wanting/trying to be a "language lawyer" in order to further pursue this issue.

I'd just like to quote a comment from dlopen's man page:
http://man7.org/linux/man-pages/man3/dlopen.3.html

           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. */

The last time I checked this, maybe around 2013 before the "2013 Technical Corrigendum" become a thing, I remember (hopefully correctly) that, in the same man page, the officially recommended way was still to use the tricky cast. After that, at some point, I believe the comment has been updated along with the code in the example to use the "normal" cast instead of that monstrosity.

Anyway, that man page was the reason for me to get used with this counter-intuitive cast style for years. I'm happy to hear now that it's not really necessary anymore. Probably, given my super-conservative nature I'll continue to use this trick for a few more years until even "pretty old" compilers will be guaranteed to non treat this as "undefined behavior", but it's good to know that things have changed.

Thanks again for the research!
Vlad

P.S.

Thanks to https://web.archive.org, I was able to see how that same man page looked several years ago, back in 2012: https://web.archive.org/web/20120402182207/http://man7.org/linux/man-pages/man3/dlopen.3.html

In the same example, the code + comment were:

           /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
              would seem more natural, but the C99 standard leaves
              casting from "void *" to a function pointer undefined.
              The assignment used below is the POSIX.1-2003 (Technical
              Corrigendum 1) workaround; see the Rationale for the
              POSIX specification of dlsym(). */

           *(void **) (&cosine) = dlsym(handle, "cos");

So, I'm happy that I remembered it correctly!

from tilck.

PetarKirov avatar PetarKirov commented on May 17, 2024

Digging a bit further, is kind of a mess.

  • C89 explicitly listed it as undefined behavior:

    A.6.2

    • A pointer to a function is converted to a pointer to an object or a pointer to an object is converted to a pointer to a function (3.3.4).

    Yet, it also lists it as a common extension:

    A.6.5.7 Function pointer casts

    A pointer to an object or to void may be cast to a pointer to a function, allowing data to be invoked as a function (3.3.4). A pointer to a function may be cast to a pointer to an object or to void , allowing a function to be inspected or modified (for example, by a debugger) (3.3.4).

  • C99 doesn't list it as undefined behavior and again only mentions it under common extensions:

    J.5.7 Function pointer casts

    1. A pointer to an object or to void may be cast to a pointer to a function, allowing data to be invoked as a function (6.5.4).
    2. A pointer to a function may be cast to a pointer to an object or to void, allowing a function to be inspected or modified (for example, by a debugger) (6.5.4).
  • In C++98-03 it is not undefined behavior, but illegal, meaning that the compiler is required to diagnose it.

  • In C++11 it's conditionally supported:

    5.2.10 Reinterpret cast

    Converting a pointer to a function into a pointer to an object type or vice versa is conditionally-supported.
    The meaning of such a conversion is implementation-defined, except that if an implementation supports
    conversions in both directions, converting a prvalue of one type to the other type and back, possibly with
    different cv-qualification, shall yield the original pointer value.

  • And certain versions of Posix even require it (in others it's mentioned only for dlsym):

    2.12.3 Pointer Types

    All function pointer types shall have the same representation as the type pointer to void. Conversion of a function pointer to void * shall not alter the representation. A void * value resulting from such a conversion can be converted back to the original function pointer type, using an explicit cast, without loss of information.

    Note:
    The ISO C standard does not require this, but it is required for POSIX conformance.

from tilck.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.