Rust如何实现仅编译时指针的安全性? [英] How does Rust achieve compile-time-only pointer safety?

查看:99
本文介绍了Rust如何实现仅编译时指针的安全性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在某处读到了一种以指针为特征的语言,由于各种原因,编译器不可能在编译时完全决定所有指针是否正确使用和/或有效(指有效对象),因为从本质上讲,这将构成解决暂停问题的方法.从直觉上讲,这并不奇怪,因为在这种情况下,我们可以推断出编译期间程序的运行时行为,类似于

I have read somewhere that in a language that features pointers, it is not possible for the compiler to decide fully at compile time whether all pointers are used correctly and/or are valid (refer to an alive object) for various reasons, since that would essentially constitute solving the halting problem. That is not surprising, intuitively, because in this case, we would be able to infer the runtime behavior of a program during compile-time, similarly to what's stated in this related question.

但是,据我所知,Rust语言要求完全在编译时检查指针(没有与指针相关的未定义行为,至少没有安全"指针,并且没有无效指针"或空"指针"运行时异常).

However, from what I can tell, the Rust language requires that pointer checking be done entirely at compile time (there's no undefined behavior related to pointers, "safe" pointers at least, and there's no "invalid pointer" or "null pointer" runtime exception either).

假设Rust编译器不能解决停止问题,那么谬论在哪里?

Assuming that the Rust compiler doesn't solve the halting problem, where does the fallacy lie?

  • 是否确实没有在编译时完全完成指针检查,并且Rust的智能指针与C中的原始指针相比仍然会引入一些运行时开销?
  • 还是Rust编译器可能无法做出完全正确的决定,并且有时需要只信任其中一个生命周期注释(使用<'lifetime_ident>语法的注释)来仅信任Programmer™?在这种情况下,这是否意味着指针/内存安全保证不是100%,仍然依赖程序员编写正确的代码?
  • 另一种可能性是Rust指针在某种意义上是非通用的"或受限制的,因此编译器可以在编译时完全推断其属性,但它们不如e有用. G. C中的原始指针或C ++中的智能指针.
  • 也许这是完全不同的东西,我误解了
    { "pointer", "safety", "guaranteed", "compile-time" }的一个或多个.
  • Is it the case that pointer checking isn't done entirely at compile-time, and Rust's smart pointers still introduce some runtime overhead compared to, say, raw pointers in C?
  • Or is it possible that the Rust compiler can't make fully correct decisions, and it sometimes needs to Just Trust The Programmer™, probably using one of the lifetime annotations (the ones with the <'lifetime_ident> syntax)? In this case, does this mean that the pointer/memory safety guarantee is not 100%, and still relies on the programmer writing correct code?
  • Another possibility is that Rust pointers are non-"universal" or restricted in some sense, so that the compiler can infer their properties entirely during compile-time, but they are not as useful as e. g. raw pointers in C or smart pointers in C++.
  • Or maybe it is something completely different and I'm misinterpreting one or more of
    { "pointer", "safety", "guaranteed", "compile-time" }.

推荐答案

免责声明:我有点着急,所以这有点曲折.随时清理它.

Disclaimer: I'm in a bit of a hurry, so this is a bit meandering. Feel free to clean it up.

语言设计师讨厌和交易的一个鬼nea俩;基本上是这样的:Rust只能推断'static生存期(用于全局变量和其他整个程序的生存期)和堆栈的生存期( ie 局部).变量:它不能表示或解释 heap 分配的有效期.

The One Sneaky Trick That Language Designers Hate™ is basically this: Rust can only reason about the 'static lifetime (used for global variables and other whole-program lifetime things) and the lifetime of stack (i.e. local) variables: it cannot express or reason about the lifetime of heap allocations.

这意味着几件事.首先,所有处理堆分配的库类型( Box<T>Rc<T>Arc<T>)都拥有它们指向的东西.结果,它们实际上并不需要 生存期.

This means a few things. First of all, all of the library types that deal with heap allocations (i.e. Box<T>, Rc<T>, Arc<T>) all own the thing they point to. As a result, they don't actually need lifetimes in order to exist.

需要的生存期是访问智能指针的内容时.例如:

Where you do need lifetimes is when you're accessing the contents of a smart pointer. For example:

let mut x: Box<i32> = box 0;
*x = 42;

第二行幕后发生的事情是这样的:

What is happening behind the scenes on that second line is this:

{
    let box_ref: &mut Box<i32> = &mut x;
    let heap_ref: &mut i32 = box_ref.deref_mut();
    *heap_ref = 42;
}

换句话说,由于Box并不是魔术,所以我们必须告诉编译器如何将其转换为正常运行的工厂借用指针.这就是DerefDerefMut特性的用途.这就提出了一个问题:heap_ref的寿命到底是什么?

In other words, because Box isn't magic, we have to tell the compiler how to turn it into a regular, run of the mill borrowed pointer. This is what the Deref and DerefMut traits are for. This raises the question: what, exactly, is the lifetime of heap_ref?

对此的答案是DerefMut的定义(因为我很着急,因此需要记忆):

The answer to this is in the definition of DerefMut (from memory because I'm in a hurry):

trait DerefMut {
    type Target;
    fn deref_mut<'a>(&'a mut self) -> &'a mut Target;
}

就像我之前说过的那样,Rust 绝对不能谈论堆寿命".相反,它必须将已分配堆的i32的生存期与它拥有的唯一其他生存期联系在一起:Box的生存期.

Like I said before, Rust absolutely cannot talk about "heap lifetimes". Instead, it has to tie the lifetime of the heap-allocated i32 to the only other lifetime it has on hand: the lifetime of the Box.

这意味着复杂的"事物没有可表达的生命周期,因此必须拥有他们所管理的事物.当您将复杂的智能指针/句柄转换为简单的借用指针时, 是必须引入生命周期的时刻,并且通常只使用句柄本身的生命周期.

What this means is that "complicated" things don't have an expressible lifetime, and thus have to own the thing they manage. When you convert a complicated smart pointer/handle into a simple borrowed pointer, that is the moment that you have to introduce a lifetime, and you usually just use the lifetime of the handle itself.

实际上,我应该澄清一下:句柄的生存期"是指当前存储句柄的变量的生存期":生存期实际上是针对存储的,表示.这通常就是为什么Rust的新手无法解决为什么他们不能做类似的事情时会被绊倒的原因:

Actually, I should clarify: by "lifetime of the handle", I really mean "the lifetime of the variable in which the handle is currently being stored": lifetimes are really for storage, not for values. This is typically why newcomers to Rust get tripped up when they can't work out why they can't do something like:

fn thingy<'a>() -> (Box<i32>, &'a i32) {
    let x = box 1701;
    (x, &x)
}

但是...我知道盒子会继续存在,为什么编译器会说不呢?!" 因为Rust无法推断堆寿命和必须&x的生存期绑定到变量 x,而不是不是它指向的堆分配.

"But... I know that the box will continue to live on, why does the compiler say it doesn't?!" Because Rust can't reason about heap lifetimes and must resort to tying the lifetime of &x to the variable x, not the heap allocation it happens to point to.

这篇关于Rust如何实现仅编译时指针的安全性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆