为什么 Rust 的原始指针可以访问超出范围的结构变量的函数和部分字段信息?

问题描述 投票:0回答:1

我想像

*const
一样使用Rust原始指针来重现释放后使用的安全问题,但是当我使用原始指针访问字段或调用已释放的结构变量的函数时,没有发生恐慌。

这是我的代码:

new
方法用于更方便地创建结构。
as_ptr
方法用于返回结构本身的原始指针。

pub struct Foo{
    data: Vec<u8>,
}

impl Foo{
    pub fn new(data: &[u8]) -> Foo{
        Foo{ data: data.to_vec() }
    }
    pub fn as_ptr(&self) -> *const Foo{
        // return a raw pointer of this struct
        self as *const Foo    
    }
    pub fn test(&self){
        println!("test");
    }
}
上面的

test
方法和下面的
use_raw_ptr
方法是为了重现免费问题后的使用。

pub unsafe fn use_raw_ptr(ptr: *const Foo){
    println!("{:?}", (*ptr).data);
}

测试时,我在

Foo
块中创建了一个
foo
结构变量
match
,我想这应该是
foo
变量的范围。如果
foo
合法,则
p
的原始指针被传递给
data
。在
match
块之后,我尝试使用
p
调用
test
的函数
Foo
并访问
data
foo
字段,我想应该出现自由后使用问题,因为
foo
应该是已经释放了。

fn main(){
    let data: Option<&[u8]> = Some(b"abc");
    let p = match data{
        Some(data) => {
            let foo = Foo::new(data);
            foo.as_ptr();
        } 
        None => std::ptr::null(),
    };
    unsafe {(*p).test()};
    println!("{:?}", data);
    unsafe{ use_raw_ptr(p) };
}

但是,执行代码时没有出现恐慌,这是输出:

test
Some([97, 98, 99])
[192, 230, 41]

还应该提到的是,每次运行代码时

use_raw_ptr
的结果都不同,但打印结果的长度始终与输入数据匹配。请问这是不是因为释放
foo
时,还保留了
data
的长度等信息?

fn main(){
    let data: Option<&[u8]> = Some(b"abcde");
    // ... same as above
}

// output
test
Some([97, 98, 99, 100, 101])
[192, 230, 5, 252, 49]

此外,我认为

unsafe{(*p).test()}
的succecc调用的原因是它调用了
Foo
结构的函数而不是
foo
变量。我不知道这是否正确,我想知道我是否可以在这里使用原始指针访问释放的内存来使程序崩溃。

rust struct unsafe raw-pointer
1个回答
0
投票

取消引用悬空指针是未定义的行为。未定义的行为,好吧undefined意味着你不能期待任何行为,因此期望它恐慌是无效的。

换句话说,任何行为,包括但不限于不更改内存,因此值仍然在相同的内存位置,恐慌,让电脑着火,执行Doom™游戏是可能的。

© www.soinside.com 2019 - 2024. All rights reserved.