Comments (2)
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.
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
- 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).
- 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)
- Compile-out print_banner_line() and show_tilck_logo() when KERNEL_SHOW_LOGO=0 HOT 4
- Don't download twice codecov in coverage_build.yml HOT 3
- Write a unit test to trigger the error code path in fork_dup_all_handles() HOT 2
- Move kernel/fs/fat32_debug.c to tests/unit/ HOT 4
- small typo in the wiki micropython page HOT 1
- Add system tests for sys_setuid() and friends HOT 1
- Move other/musl-gcc and other/musl-g++ to scripts/templates HOT 3
- Contribution documentation is not easily found HOT 2
- Warn not to mock and wrap the same function in mocking_experiments.cpp HOT 2
- Add unit tests for functions in string_util.c HOT 4
- Add tests for simple_wildcard_match() and set_traced_syscalls_int()
- Add tests for save_param_buffer() and dump_param_buffer() HOT 2
- Unable to build on Ubuntu 21.10 HOT 5
- Distro required HOT 6
- BusyBox build error HOT 5
- Can't build: /scripts/build_toolchain "too many arguments"? HOT 7
- The newest `getrusage` test failed once on Azure Pipelines HOT 5
- [feature request] Interactive build HOT 5
- Ability to add files to the created image [feature request] HOT 7
- ./toolchain-wrapper: cannot execute: required file not found HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tilck.