最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rust - Why don't unit tests panic because of a dangling pointer? - Stack Overflow

programmeradmin1浏览0评论
fn dangle() {
    fn get_str<'a>(s: *const String) -> &'a str {
        unsafe { &*s }
    }
    
    let s = String::from("hello");
    let dangling = get_str(&s);
    drop(s);
    println!("Invalid str: {}", dangling);
}

#[test]
fn test() {
    dangle();  // it should panic, but does not
}

fn main() {
    dangle();  // panics
}

The main() function panics, as I expected. But why does the test() function run successfully?

fn dangle() {
    fn get_str<'a>(s: *const String) -> &'a str {
        unsafe { &*s }
    }
    
    let s = String::from("hello");
    let dangling = get_str(&s);
    drop(s);
    println!("Invalid str: {}", dangling);
}

#[test]
fn test() {
    dangle();  // it should panic, but does not
}

fn main() {
    dangle();  // panics
}

The main() function panics, as I expected. But why does the test() function run successfully?

Share Improve this question edited yesterday mkrieger1 23.1k7 gold badges63 silver badges79 bronze badges asked yesterday realwangliqiurealwangliqiu 4492 silver badges12 bronze badges 2
  • 2 Why do you expect dangling pointers to panic? – dumbass Commented yesterday
  • Expecting a panic is falsehood 7 or 8 programmers believe about undefined behavior – cafce25 Commented yesterday
Add a comment  | 

2 Answers 2

Reset to default 5

As described on this page, your usage of unsafe is unsound (this was done on purpose in the question) and consequently leads to undefined behaviour.

Undefined behaviour does not mean that the code will necessarily fail or panic. On the contrary, it could do anything, including working perfectly! On my computer, the main program does not panic; it simply displays a weird string and when testing it does not panic either. Even if, on my computer, the pointer does not point to an inaccessible address after drop(), the bytes at this address have been reused for something else, which looks incorrect when sent to standard output. This behaviour can change from time to time, depending on anything in the system (the system, the version of the compiler...).

That's why unsound code must be avoided; we can only detect and fix a problem by chance (if it exhibits an obvious incorrect behaviour, such as panicking). If, on the other hand, the problem simply causes data corruption, it could be detected much later during the execution, and it would be very difficult to find what was the real cause of the problem (dangling pointer here). This situation is quite common in C. Safe Rust prevents those pitfalls from happening; unsafe Rust requires the developer to uphold certain guarantees instead.

What @prog-fh says.

I just wanted to add that when working with unsafe code, it is highly recommended to use miri during testing.

miri is a linter that specifically tries to detect unsound code. It isn't guaranteed to find everything, but it's quite good at it.

To check your code with miri, run:

cargo +nightly miri test

Then, you get the following error:

error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
    --> ~\.rustup\toolchains\nightly-x86_64-pc-windows-gnu\lib\rustlib\src\rust\library\core\src\fmt\mod.rs:2653:1
     |
2653 | fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free)
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
     = note: BACKTRACE on thread `test`:
     ...
note: inside `dangle`
    --> src\main.rs:9:5
     |
9    |     println!("Invalid str: {}", dangling);
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `test`
    --> src\main.rs:14:5
     |
14   |     dangle(); // it should panic, but does not
     |     ^^^^^^^^
note: inside closure
    --> src\main.rs:13:10
     |
12   | #[test]
     | ------- in this procedural macro expansion
13   | fn test() {
     |          ^
     = note: this error originates in the macro `fmt_refs` which comes from the expansion of the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
发布评论

评论列表(0)

  1. 暂无评论