Rust严格别名?

时间:2014-10-02 14:38:48

标签: rust undefined-behavior strict-aliasing

我的理解是,由于名为"严格别名规则"。

,以下代码在C ++中具有未定义的行为。
#include <cstdint>

enum Foo : int16_t {};

void test(Foo& foo) {
    reinterpret_cast<int16_t&>(foo) = 42;
}

特别是,C ++编译器可能会完全省略赋值,因为允许假设int16_t&返回的reinterpret_castfoo指向的内存不同(类型为Foo&),因为它们的类型不同。

我的问题是,Rust是否有类似于C ++&#34;严格别名规则&#34;?换句话说,下面的等效Rust代码是否有未定义的行为?

#[repr(i16)]
enum Foo { Dummy }

unsafe fn test(foo: &mut Foo) {
    *std::mem::transmute::<&mut Foo, &mut i16>(foo) = 42;
}

修改
上面的Rust示例代码存在一个不相关的问题,test创建了一个不存在的枚举变体。所以,这里有相同的代码快速修复:

#[repr(i16)]
enum Foo { Dummy, Yummy = 42 }

unsafe fn test(foo: &mut Foo) {
    *std::mem::transmute::<&mut Foo, &mut i16>(foo) = 42;
}

1 个答案:

答案 0 :(得分:7)

我的理解是,一般Rust代码(由编译器验证)当然不包含未定义的行为(禁止编译器错误),并且Rust-the-language没有定义任何未定义的行为,与C不同。

然后,当然,可能发生的唯一未定义行为位于unsafe块或函数内。 unsafe块旨在将任何潜在危险行为封装为being safe as a wholeA post from July 2014提到Rust的编译器要求满足某些不变量,并且它通常是dangerous to break those invariants, even in unsafe blocks(事实上,它只能在unsafe块内断开)。

这些危险行为之一是pointer aliasing(似乎在LLVM本身中定义)。然而,有趣的是,LLVM文档说(强调我的):

  

因此,基于类型的别名分析,又名TBAA,又名   -fstrict-aliasing,不适用于一般未加修饰的LLVM IR

因此,似乎通常情况下,只要unsafe块没有触发其他任何不安全行为,严格别名就不会成为Rust中的问题。


话虽如此,您的具体示例可能很危险,因为它似乎与参考中的一个不安全行为相匹配:

  

原始类型中的值无效,即使在私有字段/本地中也是如此:

     
      
  • 未包含在类型定义中的枚举中的判别式
  •   

我为您的示例编写了一个小扩展,在不安全操作之前和之后显示枚举变体的二进制表示:http://is.gd/x0K9kN

如您所见,将42分配给枚举值与任何已定义的鉴别器值都不匹配。但是,如果您已将01分配给枚举值(或者已经为枚举变量定义了显式鉴别符),那么理论上该操作应该没问题。