llo*_*giq 12 unsafe undefined-behavior rust
在mutagen中,我在代码中注入了各种突变.我想改变的一件事是模式
if let Ok(x) = y { .. }.然而,这构成了相当大的挑战,因为我无法知道其类型y- 用户可以使用一元Ok变体构建自己的枚举.我仍然可以机会性地改变它,因为我们实际上有一个Result错误类型实现的情况Default使用类似于以下简化的特征:
#![feature(specialization)]
pub trait Errorer {
fn err(self, mutate: bool) -> Self;
}
impl<X> Errorer for X {
default fn err(self, _mutate: bool) -> Self {
self
}
}
impl<T, E> Errorer for Result<T, E>
where
E: Default,
{
fn err(self, mutate: bool) -> Self {
if mutate {
Err(Default::default())
} else {
self
}
}
}
Run Code Online (Sandbox Code Playgroud)
唉,实现的错误并不多Default,所以这不太有用.即使是实现Result<T, Box<Error>>也会让我们更加努力(并且完全可能).但是,鉴于我并不关心实际检查错误的代码,我想知道我是否可以通过将上述代码的变异扩展到
match Errorer::err(y, mutation) {
Ok(x) => { .. }
Err(x) => { mem::forget(x); }
}
Run Code Online (Sandbox Code Playgroud)
并有err回报Err(mem::uninitialized())变异时-所以这种行为是安全的?注意:我是Err(mem::uninitialized())从一个方法返回,只是mem::forget稍后再返回.我认为这不会让人感到恐慌,所以我们应该假设这个价值确实会被遗忘.
是这个定义的行为还是我应该期待鼻子恶魔?
Ral*_*ung 10
不,这不是定义的行为,至少不适用于所有类型.(我不能告诉你的代码是如何被称为突变的一部分,所以我不知道你有没有在这里的各类控制,但通用impl肯定使它看起来像你不知道.)这是由以下证明一段代码:
#![feature(never_type)]
use std::mem;
fn main() {
unsafe { mem::forget(mem::uninitialized::<!>()) }
}
Run Code Online (Sandbox Code Playgroud)
如果你在操场上运行它,你会看到程序死于SIGILL.ASM输出显示LLVM只是将整个程序优化为立即SIGILL,因为它使用无人居住类型的值!:
playground::main:
ud2
Run Code Online (Sandbox Code Playgroud)
一般来说,mem::uninitialized在通用代码中几乎不可能正确使用,参见例如本期rc::Weak.因此,该功能正在被弃用和替换.但这对你没有帮助; 你想做的只是完全违法的Result<T, !>.