-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
debug_asserts within libstd are not hit unless using -Zbuild-std #120539
Comments
Here is a reduced testcase (not minimal) from real (yes, broken, invoking UB) code, that, because the mentioned debug_assert is not hit, leads to a completely unrelated panic that "can't happen" because of the hint::assert_unchecked that was recently added:
(it requires optimizations to be enabled, build with See https://glandium.org/blog/?p=4354 for the full story. |
Isn't it caused by |
-O makes for a non-sensical error in a debug build. A non-optimized debug build actually doesn't fail at all (unless using -Z build-std, in which case the get_unchecked debug_assert is hit), and a release build crashes with an Illegal Instruction. I don't think this is a good position to be in to debug something like this. |
It's not so much "intended" but a known limitation since we ship a pre-built std without debug asserts. The issue will be solved eventually if/when build-std becomes stable. |
The problem is that those debug_assert are followed with hints to the compiler that what's being asserted doesn't happen. So we're in a situation where UB will lead to (rightful) crashes in release builds, but debug builds showing nothing for it at all (since they're not optimized by default), or worse, can show something completely unrelated with optimization enabled (which some might do because non-optimized code can be really slow). Someone on r/rust mentioned miri. Yes, miri finds the UB. But there are a tons of cases where miri just can't be used. It's not uncommon to ship separate debug-variants of standard libraries. Rust should probably do that, because I don't see build-std becoming usable with cargo vendor any time soon. |
Can you elaborate on that? I don't know how vendoring interacts with build-std. |
rust-src doesn't contain the dependencies for libstd, and if you have a cargo config with replace-with as per the output from cargo vendor, build-std fails to find those dependencies because they're not vendored. And they can't be vendored because the code might be built against different versions of rust, with different dependencies for libstd. There were attempts to make it work in #78790 and rust-lang/cargo#8834 but they were reverted because they caused other problems. |
Ah, that's unfortunate. Afaik we're currently not shipping more flavors of std because the combinatorial explosion would bloat rustup component sizes and build-std is the intended solution to all of those. I can't speak for all the teams but I suspect it'd take some rather strong arguments to change the position on that. Work on improving build-std would be preferable. Well, building your own toolchain might be a heavyweight alternative. |
I think that if a debug assertion triggers as a result of user code, then it would be nice for it to always obey the callers debug-assertions flag, but if the debug assertion triggers only as a result of a bug in the standard library, then it should only obey the debug-assertions flag that the standard library was compiled with. Currently, functions that are dependent on the callers debug-assertions flag are macros. I think more of these macros can be added, especially for the "unchecked" functions. e.g. |
As the author of many of std's UB-detecting debug assertions and the pointer alignment checks, I've thought about this problem a lot.
We cannot distinguish if a standard library function is calling an unsafe I'm (slowly, very slowly) trying to migrate the pointer alignment checks and also runtime checks for niches (which would cover things like null slices) out of a MIR transform and into codegen: #117473. One exciting consequence of doing this in codegen is that the checks get inserted into standard library functions that are public and generic, or only lowered to MIR for some other reason. So there is an alternative approach here which might work. We could make all the standard library UB check assertions not check |
Not entirely; the intent is to have the debug assertions for the rare case where they are useful, but we are fully aware that most users do not benefit from them in their current shape. We just haven't found a good way to ship this yet.
Shameless plug, cargo-careful also enables these checks. No idea if that works with cargo-vendor though. |
It sounds like it only works on |
|
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
Toggle assert_unsafe_precondition in codegen instead of expansion r? `@ghost` rust-lang#120539 (comment)
…i-obk Toggle assert_unsafe_precondition in codegen instead of expansion The goal of this PR is to make some of the unsafe precondition checks in the standard library available in debug builds. Some UI tests are included to verify that it does that. The diff is large, but most of it is blessing mir-opt tests and I've also split up this PR so it can be reviewed commit-by-commit. This PR: 1. Adds a new intrinsic, `debug_assertions` which is lowered to a new MIR NullOp, and only to a constant after monomorphization 2. Rewrites `assume_unsafe_precondition` to check the new intrinsic, and be monomorphic. 3. Skips codegen of the `assume` intrinsic in unoptimized builds, because that was silly before but with these checks it's *very* silly 4. The checks with the most overhead are `ptr::read`/`ptr::write` and `NonNull::new_unchecked`. I've simply added `#[cfg(debug_assertions)]` to the checks for `ptr::read`/`ptr::write` because I was unable to come up with any (good) ideas for decreasing their impact. But for `NonNull::new_unchecked` I found that the majority of callers can use a different function, often a safe one. Yes, this PR slows down the compile time of some programs. But in our benchmark suite it's never more than 1% icount, and the average icount change in debug-full programs is 0.22%. I think that is acceptable for such an improvement in developer experience. rust-lang#120539 (comment)
…i-obk Toggle assert_unsafe_precondition in codegen instead of expansion The goal of this PR is to make some of the unsafe precondition checks in the standard library available in debug builds. Some UI tests are included to verify that it does that. The diff is large, but most of it is blessing mir-opt tests and I've also split up this PR so it can be reviewed commit-by-commit. This PR: 1. Adds a new intrinsic, `debug_assertions` which is lowered to a new MIR NullOp, and only to a constant after monomorphization 2. Rewrites `assume_unsafe_precondition` to check the new intrinsic, and be monomorphic. 3. Skips codegen of the `assume` intrinsic in unoptimized builds, because that was silly before but with these checks it's *very* silly 4. The checks with the most overhead are `ptr::read`/`ptr::write` and `NonNull::new_unchecked`. I've simply added `#[cfg(debug_assertions)]` to the checks for `ptr::read`/`ptr::write` because I was unable to come up with any (good) ideas for decreasing their impact. But for `NonNull::new_unchecked` I found that the majority of callers can use a different function, often a safe one. Yes, this PR slows down the compile time of some programs. But in our benchmark suite it's never more than 1% icount, and the average icount change in debug-full programs is 0.22%. I think that is acceptable for such an improvement in developer experience. rust-lang#120539 (comment)
…i-obk Toggle assert_unsafe_precondition in codegen instead of expansion The goal of this PR is to make some of the unsafe precondition checks in the standard library available in debug builds. Some UI tests are included to verify that it does that. The diff is large, but most of it is blessing mir-opt tests and I've also split up this PR so it can be reviewed commit-by-commit. This PR: 1. Adds a new intrinsic, `debug_assertions` which is lowered to a new MIR NullOp, and only to a constant after monomorphization 2. Rewrites `assume_unsafe_precondition` to check the new intrinsic, and be monomorphic. 3. Skips codegen of the `assume` intrinsic in unoptimized builds, because that was silly before but with these checks it's *very* silly 4. The checks with the most overhead are `ptr::read`/`ptr::write` and `NonNull::new_unchecked`. I've simply added `#[cfg(debug_assertions)]` to the checks for `ptr::read`/`ptr::write` because I was unable to come up with any (good) ideas for decreasing their impact. But for `NonNull::new_unchecked` I found that the majority of callers can use a different function, often a safe one. Yes, this PR slows down the compile time of some programs. But in our benchmark suite it's never more than 1% icount, and the average icount change in debug-full programs is 0.22%. I think that is acceptable for such an improvement in developer experience. rust-lang#120539 (comment)
I've closed this because the linked PR should make the example program panic. I didn't fix all debug_asserts in libstd, and the panic message is not very informative. I hope to improve both in the future. |
STR:
It would seem the intent is for the latter to always happen, but it doesn't.
The text was updated successfully, but these errors were encountered: