首页 > 解决方案 > 转换产生无效指针的函数引用?

问题描述

我正在追踪第三方代码中的一个错误,并将其缩小到类似的范围内。

use libc::c_void;

pub unsafe fn foo() {}

fn main() {
    let ptr = &foo as *const _ as *const c_void;
    println!("{:x}", ptr as usize);
}

在稳定的 1.38.0 上运行,这会打印函数指针,但 beta (1.39.0-beta.6) 并每晚返回“1”。(游乐场

推断是什么_以及为什么行为发生了变化?

我认为正确的转换方法是foo as *const c_void,但这不是我的代码。

标签: typescastingrustundefined-behavior

解决方案


此答案基于对此问题所激发的错误报告的回复。

Rust 中的每个函数都有其单独的函数项类型,这与其他所有函数的函数项类型不同。出于这个原因,函数项类型的实例根本不需要存储任何信息——它所指向的函数从它的类型中可以清楚地看出。所以变量 x 在

let x = foo;

是大小为 0 的变量。

函数项类型在必要时隐式强制转换为函数指针类型。变量

let x: fn() = foo;

是指向任何带有签名的函数的通用指针fn(),因此需要存储指向它实际指向的函数的指针,因此 的大小x是指针的大小。

如果你获取一个函数的地址&foo,你实际上是在获取一个零大小的临时值的地址。在提交到rustrepo之前,零大小的临时对象用于在堆栈上创建分配,并&foo返回该分配的地址。自此提交以来,零大小类型不再创建分配,而是使用魔术地址 1。这解释了不同版本的 Rust 之间的差异。


推荐阅读