Skip to content

Transmute from one function pointer to another produces "can't transmute zero-sized type" #75959

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

Open
belkadan opened this issue Aug 26, 2020 · 5 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-raw-pointers Area: raw pointers, MaybeUninit, NonNull A-ZSTs Area: Zero-sized types (ZSTs). C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@belkadan
Copy link

Compiling the following cursed code:

use std::ffi::CStr;

#[repr(C)]
struct ObjCObject {
  isa: isize
}

#[repr(transparent)]
#[derive(Clone,Copy)]
struct Selector(*const u8);

#[link(name = "objc")]
extern "C" {
  fn sel_registerName(name: *const u8) -> Selector;
  fn objc_getClass(name: *const u8) -> Option<&'static ObjCObject>;
  fn objc_msgSend(); // see below
}

fn main() {
  #[link(name = "Foundation", kind = "framework")]
  extern {}

  unsafe {
    let url_class = objc_getClass("NSURL\0".as_ptr()).unwrap();
    let description_sel = sel_registerName("description\0".as_ptr());
    let description_method = std::mem::transmute::<_, unsafe extern "C" fn(_, _) -> _>(objc_msgSend);
    let description_obj: *const ObjCObject = description_method(url_class, description_sel);

    let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
    let utf8_method = std::mem::transmute::<_, unsafe extern "C" fn(_, _) -> _>(objc_msgSend);
    let utf8_ptr = utf8_method(description_obj, utf8_sel);
    println!("{}", CStr::from_ptr(utf8_ptr).to_string_lossy());
  }
}

Produces the following opaque error:

error[E0591]: can't transmute zero-sized type
  --> <anon>:26:30
   |
26 | ...hod = std::mem::transmute::<_, unsafe extern "C" fn(_, _) -> _>(objc_...
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: source type: unsafe extern "C" fn() {objc_msgSend}
   = note: target type: unsafe extern "C" fn(&ObjCObject, Selector) -> *const ObjCObject
   = help: cast with `as` to a pointer instead

I'm not exactly sure why transmute won't let me go from one function pointer type to another, but even if that restriction remains, the error message could be more helpful. (My workaround was to use as isize before invoking transmute.)

Meta

rustc --version --verbose:

rustc 1.47.0-nightly (5180f3da5 2020-08-23)
binary: rustc
commit-hash: 5180f3da5fd72627a8d38558ad1297df38793acd
commit-date: 2020-08-23
host: x86_64-apple-darwin
release: 1.47.0-nightly
LLVM version: 11.0
@belkadan belkadan added the C-bug Category: This is a bug. label Aug 26, 2020
@scottmcm
Copy link
Member

Observe the following bit specifically

note: source type: unsafe extern "C" fn() {objc_msgSend}
                                          ^^^^^^^^^^^^^^

That's the unnamable ZST type, not actually a function pointer type.

If you update the lines to cast to a function pointer type first (such as as follows), it'll do what you expect:

    let utf8_method = std::mem::transmute::<_, unsafe extern "C" fn(_, _) -> _>(objc_msgSend as unsafe extern "C" fn());

@belkadan
Copy link
Author

Uh, hm. I suppose that makes sense, since you can't, like, store a function somewhere, but I don't think I would have thought of it on my own. I'm still fairly new to Rust, though, so I can't properly evaluate whether a more specific diagnostic is worth it.

@tesuji
Copy link
Contributor

tesuji commented Aug 27, 2020

Yeah, this is a trap that people come from C/C++ fall for: #75239

@camelid camelid added A-raw-pointers Area: raw pointers, MaybeUninit, NonNull A-ZSTs Area: Zero-sized types (ZSTs). labels Oct 7, 2020
@nagisa nagisa added the A-diagnostics Area: Messages for errors, warnings, and lints label Oct 7, 2020
@Noratrieb Noratrieb added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 5, 2023
@clouds56

This comment was marked as off-topic.

@scottmcm

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-raw-pointers Area: raw pointers, MaybeUninit, NonNull A-ZSTs Area: Zero-sized types (ZSTs). C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants