Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should Rust permit conversions between pointers to data and pointers to functions? #309

Closed
eternaleye opened this issue Feb 16, 2017 · 9 comments

Comments

@eternaleye
Copy link

From rust-lang/rfcs#1861 (comment)

@briansmith

Maybe we're talking past each other, but I would expect an extern type T to be guaranteed to not be a function pointer, just like struct T; is guaranteed to not point to a function in C.

Ah, I was not aware of that! (But also slight terminology tweak: It'd be *const T, not T, that would be a function pointer.) For anyone else who may have been in the same position as I was, the C99 standard says:

6.3.2.3:8 A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.

(As this gives no conversions between data pointer types and function pointer types, such conversions are undefined, and thus a pointer to one can't possibly be valid as a pointer to the other.)

The rationale I saw given when I looked was that data and function pointers may not be the same size.

However, Rust is not C, and this should probably fall under the aegis of the Rust unsafe semantics - permitting it may be of value. I've filed an issue raising that question.

Note that this requires having function pointer types, which we currently do not , and was something I thought RFC 1861 might make possible - the closest is a kind of "function reference of static lifetime" that is syntactically not a reference at all :(

@briansmith
Copy link

Disallowing data <-> function pointer/reference casting makes static (and in some cases, dynamic) analysis simpler. It would be easy to add an opaque extern fn type analogous to opaque extern (data) types.

Note that you probably don't want to have *mut function pointer types, but you do want to have *mut opaque data types.

@Nemo157
Copy link
Member

Nemo157 commented Feb 17, 2017

One of the other reasons for this limitation is the Harvard architecture. Any hardware using that architecture has two entirely separate namespaces for data and function pointers, which may be differing sizes, and may overlap each other.

I'm not sure if there are any modern architectures that are designed like that, but the AVR and PIC are definitely architectures I could see Rust being used on.

@Ericson2314
Copy link

@Nemo157 I like what I understand is the LLVM approach of supporting multiple address spaces, where any type of object can go anywhere, and higher layers enforce if certain types are restricted to certain address spaces.

@jethrogb
Copy link

If you write a JIT or use thunks in Rust, you'll need to do this. I think writing a JIT or using thunks is a pretty legitimate use case that Rust should support (unsafely).

@strega-nil
Copy link

@jethrogb I would argue that falls under "implementation defined". I don't even think it's possible to write a cross-platform JIT.

@eternaleye
Copy link
Author

@ubsan: Sure, but that's distinct from it being UB. An implementation may take implementation-defined behavior and say it's undefined, but not vice-versa. Relying on UB is always wrong; relying on implementation-defined behavior is valid if you condition on the implementation.

In C, this is UB, not implementation-defined behavior - if Rust makes it implementation-defined, that is itself a change.

@strega-nil
Copy link

strega-nil commented Apr 1, 2017

@eternaleye I don't believe it is. At least in C++:

Any pointer to function can be converted to a pointer to a different function type. Calling the function through a pointer to a different function type is undefined, but converting such pointer back to pointer to the original function type yields the pointer to the original function.

On some implementations (in particular, on any POSIX compatible system as required by dlsym), a function pointer can be converted to void* or any other object pointer, or vice versa. If the implementation supports conversion in both directions, conversion to the original type yields the original value, otherwise the resulting pointer cannot be dereferenced or called safely.

(for reinterpret_cast)

@strega-nil
Copy link

Apparently, C and C++ differ here. I do not get C...

@RalfJung RalfJung transferred this issue from rust-lang/rust-memory-model Nov 29, 2021
@JakobDegen
Copy link
Contributor

Closing in favor of #72 , #340 , and some T-lang issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants