Skip to content

Raw function pointers do not behave as expected. #47615

@brunoczim

Description

@brunoczim

A segmentation fault happens when using as_ref on a raw function pointer.
This code does not behave as expected:

fn foo() {
    println!("Hello, World!");
}

fn main() {
    unsafe {
        let f = (foo as *const fn()).as_ref().unwrap();
        f();
    }
}

This results in:

bruno@debian:~/Documents/rust$ rustc -o test test.rs 
bruno@debian:~/Documents/rust$ ./test 
Segmentation fault
bruno@debian:~/Documents/rust$ rust-gdb ./test 
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test...done.
(gdb) run
Starting program: /home/bruno/Documents/rust/test 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x000055555555b27c in test::main::h0eddcc39ebf1578f ()
(gdb) bt
#0  0x000055555555b27c in test::main::h0eddcc39ebf1578f ()
#1  0x000055555555b0b3 in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hc46a3cd2285c1402 ()
#2  0x00005555555664e8 in std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::ha09bfb8724951432 () at libstd/rt.rs:59
#3  std::panicking::try::do_call::h976c8164fad81bcc () at libstd/panicking.rs:479
#4  0x000055555557093f in __rust_maybe_catch_panic () at libpanic_unwind/lib.rs:102
#5  0x000055555555b700 in std::panicking::try::h1db13937c8e2cbb4 () at libstd/panicking.rs:458
#6  std::panic::catch_unwind::h3c1f03b328c42bbe () at libstd/panic.rs:358
#7  std::rt::lang_start_internal::h090df5551a0da347 () at libstd/rt.rs:58
#8  0x000055555555b097 in std::rt::lang_start::h771801e75e92adce ()
#9  0x000055555555b2ae in main ()
(gdb) 

The code above would be necessary because the code below does not compile:

fn foo() {
    println!("Hello, World!");
}

fn main() {
    unsafe {
        let f = (&foo as *const fn()).as_ref().unwrap();
        f();
    }
}

It results in:

error[E0606]: casting `&fn() {foo}` as `*const fn()` is invalid
 --> test.rs:7:17
  |
7 |         let f = (&foo as *const fn()).as_ref().unwrap();
  |                 ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

The solution is to use something like:

fn foo() {
    println!("Hello, World!");
}

fn main() {
    unsafe {
        let f = (&(foo as *const fn()) as *const *const fn() as *const fn()).as_ref().unwrap();
        f();
    }
}

This works fine.
Rust version:

rustc 1.25.0-nightly (da569fa9d 2018-01-16)
binary: rustc
commit-hash: da569fa9ddf8369a9809184d43c600dc06bd4b4d
commit-date: 2018-01-16
host: x86_64-unknown-linux-gnu
release: 1.25.0-nightly
LLVM version: 4.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions