gpt4 book ai didi

Rust FFI 和别名 : C -> Rust -> C -> Rust call stacks with C values being aliased: Undefined Behaviour?

转载 作者:行者123 更新时间:2023-12-05 03:31:30 25 4
gpt4 key购买 nike

在以下情况下,我正在努力思考 Rust 的别名规则:

假设我们在 C 中有一个内存分配。我们将指向该分配的指针传递给 Rust。 Rust 函数对分配做一些事情,然后回调到 C 代码(没有任何参数),其中另一个 Rust 函数使用与参数相同的分配被调用。现在,让我们假设只有第一个 Rust 函数获得可变引用。

调用堆栈如下所示:

Some C Code (owns data)
Rust(pointer as &mut)
Some C code (does not get parameters from Rust)
Rust(pointer as &)

作为一个简短的例子,我们假设有以下两个文件:测试.c

#include <stdio.h>
#include <stdlib.h>

void first_rust_function(int * ints);
void another_rust_function(const int * ints);
int * arr;
void called_from_rust() {
another_rust_function(arr);
}
int main(int argc, char ** argv) {
arr = malloc(3*sizeof(int));
arr[0]=3;
arr[1]=4;
arr[2]=53;
first_rust_function(arr);
free(arr);
}

测试.rs

use std::os::raw::c_int;
extern "C" { fn called_from_rust(); }
#[no_mangle]
pub extern "C" fn first_rust_function(ints : &mut [c_int;3]) {
ints[1] = 7;
unsafe { called_from_rust() };
}
#[no_mangle]
pub extern "C" fn another_rust_function(ints : &[c_int;3]) {
println!("Second value: {}", ints[1])
}

(为了完整起见:运行此代码会打印“第二个值:7”)

请注意,从 Rust (called_from_rust()) 回调 C 没有任何参数。因此,Rust 编译器没有任何人可能从指向的值中读取的信息。

我的直觉告诉我这是未定义的行为,但我不确定。

我快速浏览了 Stacked Borrows,发现违反了该模型。在上面的示例中,只有 Rule (protector) 被破坏了,但是如果 first_rust_function(ints : &mut [c_int;3]) 仍然会使用 ints 在调用 called_from_rust() 之后还会违反其他规则。

但是,我还没有找到任何官方文档说明 Stacked Borrows 是 Rust 编译器使用的别名模型,并且在 Stacked Borrows 下被认为未定义的所有内容实际上在 Rust 中都是未定义的。天真地,这看起来与将 &mut 强制转换为 & 非常相似,因此它实际上可能是理智的,但考虑到 called_from_rust() 不采用引用作为参数,我认为这个推理不适用。

这让我想到了实际的问题:

  • 上面的代码是否调用了未定义的行为(为什么/为什么不调用?)
  • 如果未定义:如果 called_from_rust() 将指针作为参数并将其向前传递,那么行为是否定义良好:void called_from_rust(const int * i) { another_rust_function (一世); }?
  • 如果两个 Rust 函数都使用 &mut [c_int;3] 会怎样?

最佳答案

Is the above code invoking undefined behaviour?

是的,您违反了 Rust 的指针别名规则。依赖 Stacked Borrows 规则有点可疑,因为正如您所暗示的,我认为它没有被正式采用为 Rust 的内存访问模型(即使它只是对当前语义的形式化)。然而, 一个实用而具体的规则是 LLVM 的 noalias Rust 编译器在 &mut 上使用的属性参数。

noalias

This indicates that memory locations accessed via pointer values based on the argument or return value are not also accessed, during the execution of the function, via pointer values not based on the argument or return value. ...

既然你访问了ints[1]another_rust_function来自基于 ints 的指针在 first_rust_function在执行该功能期间,这是违规行为。鉴于这种未定义的行为,我相信编译器完全有权让代码打印“第二个值:4”。


Would the behaviour be well-defined if called_from_rust() would have the pointer as parameter and pass it forward: void called_from_rust(const int * i) { another_rust_function(i); }?

是的,这将使它定义明确。您可以看到,因为 Rust 借用检查器可以看到该值可以在 called_from_rust() 中使用并将防止不当使用 ints围绕那个电话。


What if both Rust functions were using &mut [c_int;3]?

如果您使用上面的修复方法,其中第二个借用是基于第一个,那么就没有问题。如果你不这样做,那就更糟了。

关于Rust FFI 和别名 : C -> Rust -> C -> Rust call stacks with C values being aliased: Undefined Behaviour?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70633412/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com