0

Here's some code I generated using c2rust and then cleaned up a bit:

#![feature(libc)]
extern crate libc;

use libc::*;
use std::mem::transmute;

extern "C" {
    #[no_mangle]
    fn read(__fd: c_int, __buf: *mut c_void, __nbytes: c_ulong) -> c_long;
    #[no_mangle]
    fn mmap(
        __addr: *mut c_void,
        __len: c_ulong,
        __prot: c_int,
        __flags: c_int,
        __fd: c_int,
        __offset: c_long,
    ) -> *mut c_void;
}

pub fn main() {
    unsafe {
        let buf: *mut c_void = mmap(
            0 as *mut c_void,
            256i32 as c_ulong,
            0x1i32 | 0x2i32 | 0x4i32,
            0x2i32 | 0x20i32,
            -1i32,
            0i32 as c_long,
        );
        read(0i32, buf, 256i32 as c_ulong);
        transmute::<*mut c_void, Option<unsafe extern "C" fn() -> ()>>(buf).unwrap()();
    }
}

While I understand what it does, I'm not sure how to interpret the last expression. What does Option<unsafe extern "C" fn() -> ()> mean?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
d33tah
  • 10,999
  • 13
  • 68
  • 158
  • If you understand what it does, how can you not know what a line of code does? What exactly do you expect from an answer? – Shepmaster Apr 20 '19 at 17:26
  • @Shepmaster basically I was trying to understand the strange syntax of casting to function pointers in Rust. I added an answer with my notes that details the pieces I don't understand yet. – d33tah Apr 20 '19 at 17:28
  • I believe your question is answered by the answers of [How do I make a struct for FFI that contains a nullable function pointer?](https://stackoverflow.com/q/54572985/155423). If you disagree, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Apr 20 '19 at 17:30

1 Answers1

-1

We're trying to call an unsafe extern "C" fn() -> (), which is basically a function with no arguments and no return type. My first attempt was to just use the as keyword, as defined in transmute's documentation. I got the following error:

error[E0605]: non-primitive cast: `*mut libc::c_void` as `unsafe extern "C" fn()`
  --> wx.rs:32:9
   |
32 |         (buf as unsafe extern "C" fn() -> ())();
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait

It looks like the function is a non-primitive type and this is why I need transmute. I tried the following:

transmute::<
    *mut c_void,
    unsafe extern "C" fn() -> ()
>(buf)();

And the code compiled and actually ran as expected.

What I still don't understand is why Option was used by c2rust, but the code works fine without it. It appears that unsafe and extern "C" can also be dropped and the code still works, at least for me.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
d33tah
  • 10,999
  • 13
  • 68
  • 158