在实现两个段错误的类型上从特征A转换为特征B.

Dan*_*ath 2 unsafe segmentation-fault rust

几天前,有一个关于OOP的问题想要使用downcast来解决这个问题.作为一个自我挑战,我试图解决使用std::mem::transmute和不安全块的问题,这产生了分段错误.

这是Rust Playground完整代码.

代码的违规部分是这样的:

unsafe {
    let storage =
        mem::transmute::<&mut Box<AnyStorable + 'static>, &mut Box<Insertable<C>>>(x);
    println!("{:#?}", x);
    storage.insert(component); // This segfaults
};
Run Code Online (Sandbox Code Playgroud)

运行时会产生段错误:

/root/entrypoint.sh:line 7:5分段错误超时--signal = KILL $ {timeout}"$ @"

但是,当我更换此行时:

let storage =
    mem::transmute::<&mut Box<AnyStorable + 'static>, &mut Box<Insertable<C>>>(x);
Run Code Online (Sandbox Code Playgroud)

有:

let storage =
    mem::transmute::<&mut Box<AnyStorable + 'static>, &mut Box<VecStorage<C>>>(x);
Run Code Online (Sandbox Code Playgroud)

有用.为什么第一行失败而第二行没有?

Ste*_*fan 6

Box<SomeTrait>存储两个指针:一个指向对象,一个指向vtable.Box<SomeType>只存储一个指针:一个指向对象.

您可以在示例中使用以下代码查看大小:

println!("{}", mem::size_of::<Box<AnyStorable + 'static>>());
println!("{}", mem::size_of::<Box<Insertable<C>>>());
println!("{}", mem::size_of::<Box<VecStorage<C>>>());
Run Code Online (Sandbox Code Playgroud)

调用transmute改变Box意志的特征打破了vtable:不同特征的vtable不兼容.

呼吁transmute改变从引用Box<SomeTrait>到的参考Box<SomeType>(和类型恰好是正确的)恰好作品,因为它只会使用第一个指向对象的指针,忘记性状.

胖子指针(即带有vtable的数据指针)的内部表示被定义TraitObject,只能在夜间构建中访问.虽然不太可能表示可能会改变数据指针不再是第一个指针的方式,这会破坏第二个指针transmute.

文档TraitObject也值得一读.

(虽然transmute确保传递类型的大小相等,但您传递的是对类型的引用 - 它们总是只有一个指针大.它不会检查这些引用所指向的类型.)

  • 如果我没有弄错,则不指定胖指针中字段的顺序.因此嬗变成`&mut Box <VecStorage <C >>`是不安全的. (2认同)