mem :: forget(mem :: uninitialized())定义的行为是什么?

时间:2018-05-04 22:52:43

标签: rust undefined-behavior unsafe

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
        }
    }
}

唉,实现Default的错误并不多,所以这是 不太有用。甚至Result<T, Box<Error>>的实现也会给出 我们更加努力(并且完全可能)。但是,鉴于我 不关心代码实际检查错误,我想知道我是否可以 通过将上述代码的变异扩展到

来进行一般实现
match Errorer::err(y, mutation) {
    Ok(x) => { .. }
    Err(x) => { mem::forget(x); }
}

并且在变异时让err返回Err(mem::uninitialized()) - 这也就是这样 行为安全吗?注意:我从方法返回Err(mem::uninitialized()), 以后才到mem::forget。我认为这不会让人感到恐慌,所以我们应该这样做 假设这个价值确实会被遗忘。

这是定义的行为还是我应该期待鼻子恶魔?

1 个答案:

答案 0 :(得分:10)

不,这不是定义的行为,至少不适用于所有类型。 (我不知道你的代码将如何作为变异的一部分被调用,所以我不知道你是否可以控制这里的类型,但是通用impl肯定会使它看起来像你没有。)以下代码证明了这一点:

#![feature(never_type)]
use std::mem;

fn main() {
    unsafe { mem::forget(mem::uninitialized::<!>()) }
}

如果您run this on the playground,您将看到程序死于SIGILL。 ASM输出显示LLVM只是将整个程序优化为立即SIGILL,因为它使用无人类型!的值的方式:

playground::main:
    ud2

一般来说,在通用代码中正确使用mem::uninitialized几乎是不可能的,例如, this issue of rc::Weak。因此,该函数正处于deprecated and replaced的过程中。但这对你没有帮助;你想要做的只是Result<T, !>完全违法。