在 iter::count 上运行收集时收到“非法指令”

tsh*_*ang 4 linux rust

运行这个:

fn main() {
    std::iter::count(1i16, 3).collect::<Vec<i16>>();
}
Run Code Online (Sandbox Code Playgroud)

我得到:

线程 '' 在 '容量溢出' 中恐慌,/home/tshepang/projects/rust/src/libcore/option.rs:329

这就是我在运行时所期望的:

fn main() {
    std::iter::count(1i8, 3).collect::<Vec<i8>>();
}
Run Code Online (Sandbox Code Playgroud)

但相反,我得到了这个:

非法指令

此外,syslog 显示以下行:

12 月 27 日 08:31:08 thome 内核:[170925.955841] 陷阱:main[30631] 陷阱无效操作码 ip:7f60ab175470 sp:7fffbb116578 error:0 in main[7f60ab15c000+5b000]

She*_*ter 6

这是一次有趣的冒险。

Iter::collect 简单地调用 FromIterator::from_iter

Vec的实现FromIterator向迭代器询问其大小,然后分配内存:

let (lower, _) = iterator.size_hint();
let mut vector = Vec::with_capacity(lower);
Run Code Online (Sandbox Code Playgroud)

Vec::with_capacity 计算内存的总大小并尝试分配它:

let size = capacity.checked_mul(mem::size_of::<T>())
               .expect("capacity overflow");
let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
if ptr.is_null() { ::alloc::oom() } // Important!
Run Code Online (Sandbox Code Playgroud)

在这种情况下,i8占用 1 个字节,无限迭代器的下限是std::uint::MAX。相乘,还是std::uint::MAX。当我们分配它时,我们得到一个空指针。

alloc::oom被定义为简单地中止,这是由非法指令实现的!

ani16具有不同行为的原因是因为它触发了checked_mul期望 - 您不能分配std::uint::MAX * 2字节!


在现代 Rust 中,示例将被编写为:

let (lower, _) = iterator.size_hint();
let mut vector = Vec::with_capacity(lower);
Run Code Online (Sandbox Code Playgroud)

现在两者都以相同的方式失败:

let size = capacity.checked_mul(mem::size_of::<T>())
               .expect("capacity overflow");
let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
if ptr.is_null() { ::alloc::oom() } // Important!
Run Code Online (Sandbox Code Playgroud)