-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Panic in nightly 1.83.0 and 1.84.0 with opt-level >= 1 when unwrapping Some variant #132353
Comments
This comment has been minimized.
This comment has been minimized.
Minimized: fn pop_min(mut score2head: Vec<Option<usize>>) -> Option<usize> {
loop {
if let Some(col) = score2head[0] {
score2head[0] = None;
return Some(col);
}
}
}
fn main() {
let min = pop_min(vec![Some(1)]);
println!("min: {:?}", min);
// panic happens here on beta in release mode
min.unwrap();
} |
Working on a revert for e7386b3, we can reland that mir-opt with this fixed. |
WG-prioritization assigning priority (Zulip discussion). @rustbot label -I-prioritize +P-critical |
(The revert will probably need to be beta-backported, but I'll nominate that in the PR) |
Oh cool, yes I can try to use that. |
(BTW is this written down in the dev-guide or even forge somewhere, if we can make mir-opt reland reviews easier we definitely should) |
To catch at least one pattern that was miscompiled. The test is a minimization of the MCVE reported in <rust-lang#132353>.
Looks like makes sense, though I'm still not sure which chapter it should go in. |
To catch at least one pattern that was miscompiled. The test is a minimization of the MCVE reported in <rust-lang#132353>.
I opened #132356 which marks the mir-opt as unsound (hence disabling it by default, but doesn't remove the implementation to make reland reviews easier). EDIT: updated tests that are added by #132356 to use |
Subsequent PRs won’t affect existing test cases, so I prefer |
To catch at least one pattern that was miscompiled. The test is a minimization of the MCVE reported in <rust-lang#132353>.
…to_copy, r=cjgillot Mark `simplify_aggregate_to_copy` mir-opt as unsound Mark the `simplify_aggregate_to_copy` mir-opt added in rust-lang#128299 as unsound as it seems to miscompile the MCVE reported in rust-lang#132353. The mir-opt can be re-enabled once this case is fixed. ```rs fn pop_min(mut score2head: Vec<Option<usize>>) -> Option<usize> { loop { if let Some(col) = score2head[0] { score2head[0] = None; return Some(col); } } } fn main() { let min = pop_min(vec![Some(1)]); println!("min: {:?}", min); // panic happens here on beta in release mode // but not in debug mode min.unwrap(); } ``` This MCVE is included as a `run-pass` ui regression test in the first commit. I built the ui test with a nightly manually, and can reproduce the behavioral difference with `-C opt-level=0` and `-C opt-level=1`. Locally, this ui test will fail unless it was run on a compiler built with the second commit marking the mir-opt as unsound thus disabling it by default. This PR **partially reverts** commit e7386b3, reversing changes made to 02b1be1. The mir-opt implementation is just marked as unsound but **not** reverted to make reland reviews easier. The test changes are **fully** reverted. cc `@DianQK` `@cjgillot` (PR author and reviewer of rust-lang#128299)
To catch at least one pattern that was miscompiled. The test is a minimization of the MCVE reported in <rust-lang#132353>.
…to_copy, r=cjgillot,DianQK Mark `simplify_aggregate_to_copy` mir-opt as unsound Mark the `simplify_aggregate_to_copy` mir-opt added in rust-lang#128299 as unsound as it seems to miscompile the MCVE reported in rust-lang#132353. The mir-opt can be re-enabled once this case is fixed. ```rs fn pop_min(mut score2head: Vec<Option<usize>>) -> Option<usize> { loop { if let Some(col) = score2head[0] { score2head[0] = None; return Some(col); } } } fn main() { let min = pop_min(vec![Some(1)]); println!("min: {:?}", min); // panic happens here on beta in release mode // but not in debug mode min.unwrap(); } ``` This MCVE is included as a `run-pass` ui regression test in the first commit. I built the ui test with a nightly manually, and can reproduce the behavioral difference with `-C opt-level=0` and `-C opt-level=1`. Locally, this ui test will fail unless it was run on a compiler built with the second commit marking the mir-opt as unsound thus disabling it by default. This PR **partially reverts** commit e7386b3, reversing changes made to 02b1be1. The mir-opt implementation is just marked as unsound but **not** reverted to make reland reviews easier. The test changes are **fully** reverted. cc `@DianQK` `@cjgillot` (PR author and reviewer of rust-lang#128299)
…e_to_copy, r=cjgillot,DianQK Mark `simplify_aggregate_to_copy` mir-opt as unsound Mark the `simplify_aggregate_to_copy` mir-opt added in rust-lang#128299 as unsound as it seems to miscompile the MCVE reported in rust-lang#132353. The mir-opt can be re-enabled once this case is fixed. ```rs fn pop_min(mut score2head: Vec<Option<usize>>) -> Option<usize> { loop { if let Some(col) = score2head[0] { score2head[0] = None; return Some(col); } } } fn main() { let min = pop_min(vec![Some(1)]); println!("min: {:?}", min); // panic happens here on beta in release mode // but not in debug mode min.unwrap(); } ``` This MCVE is included as a `run-pass` ui regression test in the first commit. I built the ui test with a nightly manually, and can reproduce the behavioral difference with `-C opt-level=0` and `-C opt-level=1`. Locally, this ui test will fail unless it was run on a compiler built with the second commit marking the mir-opt as unsound thus disabling it by default. This PR **partially reverts** commit e7386b3, reversing changes made to 02b1be1. The mir-opt implementation is just marked as unsound but **not** reverted to make reland reviews easier. The test changes are **fully** reverted. cc `@DianQK` `@cjgillot` (PR author and reviewer of rust-lang#128299)
…to_copy, r=cjgillot,DianQK Mark `simplify_aggregate_to_copy` mir-opt as unsound Mark the `simplify_aggregate_to_copy` mir-opt added in rust-lang#128299 as unsound as it seems to miscompile the MCVE reported in rust-lang#132353. The mir-opt can be re-enabled once this case is fixed. ```rs fn pop_min(mut score2head: Vec<Option<usize>>) -> Option<usize> { loop { if let Some(col) = score2head[0] { score2head[0] = None; return Some(col); } } } fn main() { let min = pop_min(vec![Some(1)]); println!("min: {:?}", min); // panic happens here on beta in release mode // but not in debug mode min.unwrap(); } ``` This MCVE is included as a `run-pass` ui regression test in the first commit. I built the ui test with a nightly manually, and can reproduce the behavioral difference with `-C opt-level=0` and `-C opt-level=1`. Locally, this ui test will fail unless it was run on a compiler built with the second commit marking the mir-opt as unsound thus disabling it by default. This PR **partially reverts** commit e7386b3, reversing changes made to 02b1be1. The mir-opt implementation is just marked as unsound but **not** reverted to make reland reviews easier. Test changes are **reverted if they were not pure additions**. Tests added by the original PR received `-Z unsound-mir-opts` compile-flags. cc `@DianQK` `@cjgillot` (PR author and reviewer of rust-lang#128299)
To catch at least one pattern that was miscompiled. The test is a minimization of the MCVE reported in <rust-lang#132353>. (cherry picked from commit 4d8bda3)
To catch at least one pattern that was miscompiled. The test is a minimization of the MCVE reported in <rust-lang#132353>.
[WIP] Invalidate all dereferences when encountering non-local assignments Fixes rust-lang#132353. r? ghost
@DianQK While fixing this particular MIR optimization soundness is great, I was wondering if there's any more systemic initiative to try and catch such optimization issues, such as -- for example -- differential fuzzing between running |
@matthiaskrgr maybe have some insight on fuzzing. |
I believe that @cbeuw did that kind of fuzzing, but I don't think its still running? And @shao-hua-li also does correctness fuzzing as well, but I don't think their methodology is MIR-oriented. |
What exactly would be the result we are trying to find catch? differences in executables, program output? I already implemented running |
First of all, what I am afraid of is that optimizations may accidentally introduce differences in behavior: panics, as observed here, is probably the mildest issue, changes in the results of calculations or introduction of UB would be much more concerning. I do think optimizations on MIR are good -- they apply pre-monomorphization, for one -- but code generation bugs are a pain, and thus I am wondering if any safeguard could be put in place which would stand a good chance to catch the issue early on, before it reaches users. In particular, I note that while this issue was detected on nightly, it had already "escaped" to beta, and would have been stabilized 2 weeks later. So, I was thinking of the potential ways to catch such issues, systematically, and early on:
Thus, as a stop-gap measure, my suggestion of perhaps using Differential Fuzzing on the output of interpreting unoptimized and optimized MIR with miri, which could be extended to the output of running the generated machine code. I don't have much experience with miri performance wise -- I'm happy to run Still, it may be worth the time, especially as unlike native binaries, miri does catch quite a few different kinds of UB, notably borrow-checking violations. The biggest blocker, though, would be having a good corpus + fuzzer. Absent that, it's no longer easy to spin up... |
Although I also deeply dislike miscompile (especially those caused by me :p), I often see cases where some miscompile in LLVM hidden for years. Alive2 is very useful, but we currently only run it on pre-commit prove and mostly test cases in LLVM. IMO, we can start some fuzzer with different pipeline and compare those running results. I’ll consider this, although I don’t have any experience yet. |
I have seen that cranelift is sometimes more strict than rustc and it ICEs on code that exhibits unsoundess which rustc+llvm would just wave through and compile. I already implemented something like "run miri, check if there is UB in the absence of I also have a check that runs kani https://model-checking.github.io/kani/ and checks if mir opts would cause panics and it would have detected the problem above it seems 🎉 (although I very rarely run this tbh 🙈 )
|
about the corpus, the rust repo and all its history are around 25 gb of code already, seems like a good start :)
|
This is now a discussion of how to fuzz rustc, which is much better had elsewhere.
His dissertation https://dl.acm.org/doi/pdf/10.1145/3689780 says it took 10 CPU-years of fuzzing to uncover 22 new bugs. That's low enough yield that this needs to run on a server somewhere, not in someone's dev environment (much less a shared dev environment). Infra may be willing to help run it, but someone would need to do the work to maintain the codebase. |
Sadly, for mir-opt bugs like this, the best defense we have is still to be really extra super careful when writing and reviewing them. Fuzzing and other tooling can catch some bugs, but not nearly enough.
More importantly, someone needs to sift through the reports generated by the tool, and turn them into useful bug reports. |
When calling an unwrap on a value that should be Some, i instead get an unwrap on None error. Attaching a debugger seems to show an invalid memory error.
This issue happens only when opt-level is set to at least 1, (aka in dev profile, no panic happens, and in release it does), and only happens in rust nightly 1.83.0 and 1.84.0, it does not happen on stable and nightly 1.82.0.
I'm not sure if the issue is in my code or in the sprs crate, i've filed an issue there and also here just to make sure.EDIT: managed to narrow down the bug by removing the sprs crate, this is only pure rust
Here is the repo for minimum example or in the playground, there is an even smaller reproduction in the comments
To reproduce, run
cargo run --release
which will panic, while if runningcargo run
it won't panicI've tried to run this with miri, nothing there. Also tried to run the release mode with bounds checking turned on, but nothing changed
Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: