ZhangHanDong / tao-of-rust-codes

《Rust编程之道》随书源码
https://ruststudy.github.io/tao_of_rust_docs/tao_of_rust/
MIT License
1.18k stars 170 forks source link

[十三章] 代码清单 13-13 执行报错 #291

Closed liy010 closed 3 years ago

liy010 commented 4 years ago

代码错误

其他代码没问题,这一段执行的时候出现错误

let x = vec![0, 1, 2, 3];
let y = &x as *const Vec<i32>;
unsafe {
    assert_eq!(y.read(), [0,1,2,3]);
}

Rust版本

rustc 1.43.0 (4fb7144ed 2020-04-20)  macos 10.15.4
rustc 1.43.0 (4fb7144ed 2020-04-20)  ubuntu 20.04

错误信息

MacOS
example(23006,0x105530dc0) malloc: *** error for object 0x7f868d405b10: pointer being freed was not allocated
example(23006,0x105530dc0) malloc: *** set a breakpoint in malloc_error_break to debug

Ubuntu
free(): double free detected in tcache 2
Aborted (core dumped)
zydxhs commented 4 years ago

win10 x64 + rustc 1.43 表示代码可以正常运行。 Playground 可以正常运行:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=23310eae264310b79ebff615331a0552

ZhangHanDong commented 4 years ago

噢? 我抽空看看啥情况

ZhangHanDong commented 4 years ago

@liy010 @zydxhs 这段代码出了UB

ZhangHanDong commented 4 years ago
fn main() {
    let x = [0, 1, 2, 3];
    let y = &x as *const [i32; 4];
    unsafe {
        assert_eq!(y.read(), [0,1,2,3]);
    }
}

这样没问题。

ZhangHanDong commented 4 years ago
fn main() {
    let x  = vec![0, 1, 2, 3];
    let y = &x as *const Vec<i32>;
    // std::mem::forget(x); // 增加这一行可修复
    unsafe {
        assert_eq!(std::ptr::read(y), [0,1,2,3]);  // std::ptr::read(y) 执行完也会执行析构,因为read并没有转移所有权
    }

}

上面的代码,编译没问题,但是在运行时发生了 UB:双重释放(double free)。

@liy010 @zydxhs

ZhangHanDong commented 4 years ago

这个问题需要在第二版里详细描述,暂时在第7次印刷版中增加对此issues的引用

ZhangHanDong commented 4 years ago
#[derive(Debug)]
struct My;

impl Drop for My {
    fn drop(&mut self) {
        println!("Dropping!");
    }
}

fn main() {
    let x  = My;
    let y = &x as *const My;
    // std::mem::forget(x);
    unsafe {
        let a = std::ptr::read(y);
        println!("{:?}", a);
    }
}

输出:

My
Dropping!
Dropping!
zydxhs commented 4 years ago
fn main() {
    let x = [0, 1, 2, 3];
    let y = &x as *const [i32; 4];
    unsafe {
        assert_eq!(y.read(), [0,1,2,3]);
    }
}

这样没问题。

这段代码,win10 x64 + rustc v1.45.2 编译失败:

error[E0606]: casting `&std::vec::Vec<i32>` as `*const [i32; 4]` is invalid
 --> src\main.rs:3:13
  |
3 |     let y = &x as *const [i32; 4];
  |             ^^^^^^^^^^^^^^^^^^^^^
ZhangHanDong commented 4 years ago
fn main() {
    let x = [0, 1, 2, 3];
    let y = &x as *const [i32; 4];
    unsafe {
        assert_eq!(y.read(), [0,1,2,3]);
    }
}

这样没问题。

这段代码,win10 x64 + rustc v1.45.2 编译失败:

error[E0606]: casting `&std::vec::Vec<i32>` as `*const [i32; 4]` is invalid
 --> src\main.rs:3:13
  |
3 |     let y = &x as *const [i32; 4];
  |             ^^^^^^^^^^^^^^^^^^^^^

@zydxhs 这个问题你报给 Rust 官方吧,去官方仓库那发个 issues。 估计是windows支持出了啥问题。

zydxhs commented 4 years ago
fn main() {
    let x = [0, 1, 2, 3];
    let y = &x as *const [i32; 4];
    unsafe {
        assert_eq!(y.read(), [0,1,2,3]);
    }
}

这样没问题。

这段代码,win10 x64 + rustc v1.45.2 编译失败:

error[E0606]: casting `&std::vec::Vec<i32>` as `*const [i32; 4]` is invalid
 --> src\main.rs:3:13
  |
3 |     let y = &x as *const [i32; 4];
  |             ^^^^^^^^^^^^^^^^^^^^^

又验证了一次,编译成功了。估计是增量编译导致的问题。