宣布 Rust 1.15.1

2017 年 2 月 9 日 · Rust 核心团队

Rust 团队很高兴宣布 Rust 的最新版本 1.15.1。Rust 是一种系统编程语言,专注于安全、速度和并发。

如果您已安装了旧版本的 Rust,获取 Rust 1.15.1 非常简单

$ rustup update stable

如果您还没有安装,您可以从我们网站上的相应页面 下载 Rust,并查看 GitHub 上的 1.15.1 的详细发布说明

1.15.1 稳定版中的内容

此版本修复了两个问题,一个是新 vec::IntoIter::as_mut_slice 方法中的健全性错误,另一个是回归问题,其中 Rust 发行版中的某些 C 组件 没有使用 -fPIC 编译。后者会导致可执行文件的文本部分在某些配置(包括常见的 Linux 配置)中可写,从而破坏重要的攻击缓解措施,并通过导致链接器执行更多工作来延长启动时间。对于大多数 Rust 代码库,失去只读文本部分的实际影响相对较小(因为 Rust 的类型系统是其第一道防线),但对于链接到其他代码库的 Rust,影响可能出乎意料地非常大。 PIC 问题是众所周知的,并非 Rust 特有,因此本文的其余部分将重点介绍健全性错误。

as_mut_slice 的问题,一个三行函数,是在发布 Rust 1.15.0 之后几分钟内 发现的,它提醒我们编写不安全代码的风险。

as_mut_sliceVec 类型 IntoIter 迭代器上的一个方法,它提供对正在迭代的缓冲区的可变视图。从概念上讲,它很简单:只需返回对缓冲区的引用;事实上,实现很简单,但它是不安全的,因为 IntoIter 是使用指向缓冲区的非安全指针实现的

pub fn as_mut_slice(&self) -> &mut [T] {
    unsafe {
        slice::from_raw_parts_mut(self.ptr as *mut T, self.len())
    }
}

这几乎是人们可以要求的最简单的非安全方法。你能发现错误吗?我们的审阅者没有发现!这个 API 由于它是一个标准且很小的 API 而被忽略了。这是一个复制粘贴错误,审阅者忽略了它。此方法接受一个共享引用,并从它不安全地派生出一个可变引用。这完全是错误的,因为它意味着 as_mut_slice 可以用来生成对同一缓冲区的多个可变引用,这是在 Rust 中绝对不能做的事情。

这是一个简单的示例,说明此错误将允许您错误地编写什么

fn main() {
    let v = vec![0];
    let v_iter = v.into_iter();
    let slice1: &mut [_] = v_iter.as_mut_slice();
    let slice2: &mut [_] = v_iter.as_mut_slice();
    slice1[0] = 1;
    slice2[0] = 2;
}

slice1slice2 都引用了同一个可变切片。还要注意,它们创建的迭代器 v_iter 没有声明为可变的,这表明事情有些不妥。

这里的 解决方案 很简单,只需将 &self 更改为 &mut self

pub fn as_mut_slice(&mut self) -> &mut [T] {
    unsafe {
        slice::from_raw_parts_mut(self.ptr as *mut T, self.len())
    }
}

这样,就可以维护适当的唯一性不变式,一次只能创建一个可变切片,并且 v_iter 必须声明为可变的才能提取可变切片。

因此,我们进行了更改,并发布了修复程序。在 Rust 中,我们以不破坏 API 为荣,但由于这是一个新的、次要的功能,并且当前的实现非常不健全,我们决定立即发布修复程序,希望在太多代码库采用它之前发布——也就是说,我们不认为这是一个需要仔细过渡的破坏性更改,而是一个必要的错误修复。有关 Rust 确保稳定性的方法的更多信息,请参阅 "稳定性作为交付成果" 博客文章、RFC 1122(关于语言演变)和 RFC 1105(关于库演变)。

我们仍在评估从中吸取的教训,但这提醒我们,在编写不安全代码时必须谨慎。我们有一些想法可以更早地在开发过程中发现此类问题,但尚未做出任何决定。

对于由此带来的不便,我们深表歉意。让我们开始黑客攻击吧。

1.15.1 的贡献者

我们有 2 位个人为 Rust 1.15.1 做出了贡献。 感谢!