Rust: Values with short-lived lifetimes allowed in matches when a branch returns ptr::null

Created on 29 Jan 2020  路  4Comments  路  Source: rust-lang/rust

Howdy! I had an issue with some (admittedly poor) code that seemed to behave differently in release and debug builds.

Here is a short repro of the offending code: https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=744b3dd0e3a8171675a1f2969c370915

In a debug build, this code will work as expected. In a release build, this code will sleep for an uncertain amount of time (or more likely be killed by the playground).

If both arms of the match return a &timespec, the issue becomes clear, and the compiler catches it correctly: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b788f0170f6d876aae8fc856d562b34f

It looks like the timespec in my example doesn't live long enough, and so may be freed (or even optimized out) in a release build.

Thanks so much!

Most helpful comment

This code is UB. foo has type *const timespec. You create a pointer to a temporary and store it in foo, then that temporary goes out of scope at the end of the match arm, invalidating the pointer before it is passed to nanosleep.

I suppose this is a good example of how the combination of type inference and implicit conversion from &T to *const T can lead to surprising results for users. Perhaps we could warn when we see code like let p: *const T = &{ unpromotable expr }?

All 4 comments

This code is UB. foo has type *const timespec. You create a pointer to a temporary and store it in foo, then that temporary goes out of scope at the end of the match arm, invalidating the pointer before it is passed to nanosleep.

I suppose this is a good example of how the combination of type inference and implicit conversion from &T to *const T can lead to surprising results for users. Perhaps we could warn when we see code like let p: *const T = &{ unpromotable expr }?

Is there any case where the production of a temporary from a match arm is correct behavior? Why not just make that case a well-defined compile error?

Yes. It's correct in pretty much all cases. *const T has no special semantics as far as the borrow checker is concerned. It is treated the same as if the match arm evaluated to an integer.

@ecstatic-morse Thanks for the explanation, I see how this was my fault now.

Personally, I'd appreciate a warning like that, but that seems like it'd be needlessly noisy in cases where that promotion is intentional. I'll close this issue since it was very much a problem on my end.

Thanks again!

Was this page helpful?
0 / 5 - 0 ratings