我正试图理解 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 &)
作为一个简单的例子,假设有以下两个文件:test.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);
}
test.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])
}
(为了完整性:执行此代码会打印“Second value: 7”)
请注意,从Rust调用C的回调函数(`called_from_rust()`)没有任何参数。因此,Rust编译器不具有任何人可能从指向的值中读取的信息。
我的直觉告诉我这是未定义行为,但我不确定。
我快速查看了Stacked Borrows,并且该模型被违反了。在上面的示例中,只有保护程序
Rule (protector)
被破坏,但如果first_rust_function(ints : &mut [c_int;3])
在调用called_from_rust()
之后仍然使用ints
,则还将违反其他规则。然而,我没有找到任何官方文档说明Stacked Borrows是Rust编译器使用的别名模型,并且在Stacked Borrows下考虑为未定义的所有内容都实际上在Rust中是未定义的。朴素地看,这看起来足够类似于将
&mut
强制转换为&
,因此它可能实际上是合理的,但是鉴于called_from_rust()
没有将引用作为参数传递,我不认为这种推理适用。这带我来到实际问题:
1. 上述代码是否会引起未定义的行为(为什么或为什么不会)? 2. 如果是未定义的:如果
called_from_rust()
将指针作为参数并将其传递下去,行为是否定义良好:void called_from_rust(const int * i) { another_rust_function(i); }
?
3. 如果两个Rust函数都使用&mut [c_int;3]
会怎样?
restrict
,以绑定Rust函数。 - Aiden4