-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Failed assert 2 != 2
after update to LLVM 17
#115385
Comments
2 != 2
on x86_64-fuchsia
after update to LLVM 172 != 2
after update to LLVM 17
You may already know this, but: Unless you set all the "also warn on..." flags on at once, the Rust MIR interpreter allowing something to pass should only be taken as a probabilistic statement on UB. It defaults to conservative. There are several undecided points of the Rust operational model that may become explicitly UB but are not necessarily flagged as such by miri, and even though "Rust hasn't defined it as formally always-UB" means "rustc should not be attempting to suggest LLVM optimizes based on this", we sometimes discover LLVM has added an optimization that is technically valid according to the LLVM language's model if you interpret vague things in an... interesting way. We also sometimes discover LLVM has simply added an invalid transformation, of course, which still seems more likely. "The compiler told you to reject the evidence of your eyes and ears. It was its final, most essential command." |
Thank you, yes. I should clarify that I ran the crate through MIRI to ensure that this is not the result of UB in the Rust specification of this program. I did that because the repro currently pulls in two external crates which are not guaranteed to be UB-free. You are correct that this does not guarantee that UB doesn't sneak in during the translation from Rust semantics to LLVM semantics. |
From a quick look, à la I haven't tried reducing yet so I'm not sure if the following IR has been extracted correctly, but here goes:
The diff between the two is quite small, and the reproducer should reduce nicely. I'll try doing so tomorrow if no one gets to it before then. (cc @rust-lang/wg-llvm in the meantime) update: nothing substantial on the reduction yet , and I've asked the LLVM WG for help in this zulip topic. |
Thanks for the help, I have reproduced the erroneous pass ( |
I'd love to take a look at the script: I had hoped to do exactly that, but had issues and went the other route of minimizing from the rust side (starting with |
Here's a gist of the script I'm running with |
@rustbot claim |
Upstream issue: llvm/llvm-project#65195. I shared my reduced method for this issue.
let restored_plan: TestExecutionPlan = serde_json5::from_str(config).expect("Expected a valid JSON config.");
if restored_plan.pos == 2 {
good()
} else {
bad()
}
PR coming soon (Going back to my parent's home later, so the PR will be tomorrow.). |
In case it's useful, I also completed a reduction: Reading through this a bit more closely, I think that |
Sorry I got the wrong conclusion. The error should appear in JumpThreading. 😵😵💫🥹😭 |
Unfortunately there are also still gaps between Miri and the Rust spec, as explained in Miri's readme. However, to my knowledge Miri can detect all de-facto UB that is exploited by LLVM or MIR optimizations. So a difference between the behavior of Miri and the compiled program is always one of
The main caveat is that future Miri/rustc updates can lead to UB reports in previously UB-free programs, if Miri starts detecting more of the UB permitted by the spec. |
I have reverse-engineered a minimal repro with no deps based on the miscompiled LLVM IR:
#[repr(i64)]
pub enum Boolean {
False = 0,
True = 1,
}
impl Clone for Boolean {
fn clone(&self) -> Self {
*self
}
}
impl Copy for Boolean {}
#[link(name = "auxiliary")]
extern "C" {
fn config_set_value(value: i64);
fn set_value(foo: *mut i64);
}
/// # Safety
///
/// The next call to `set_value` must set its value to either 0 or 1 if x is
/// `true`.
#[no_mangle]
pub unsafe fn foo(x: bool) {
let mut foo = core::mem::MaybeUninit::<i64>::uninit();
// SAFETY: `set_value` always initializes the i64 it is given a pointer to.
unsafe {
set_value(foo.as_mut_ptr());
}
if x {
// SAFETY: The caller has asserted that `set_value` will only set `foo`
// to either 0 or 1.
let l1 = unsafe { *foo.as_mut_ptr().cast::<Boolean>() };
if matches!(l1, Boolean::False) {
// SAFETY: We may write to `foo` here.
unsafe {
*foo.as_mut_ptr() = 0;
}
}
}
// SAFETY: `foo` is definitely initialized.
let l2 = unsafe { *foo.as_mut_ptr() };
if l2 == 2 {
bar();
}
}
#[no_mangle]
pub fn bar() {
println!("Call to bar preserved!");
}
fn main() {
let print = std::env::args().nth(1).unwrap() == "print";
let (config, x) = if print {
(2, false)
} else {
(0, true)
};
// SAFETY: (config, x) are always a valid pair to call `config_set_value`
// and `foo` with.
unsafe {
config_set_value(config);
foo(x);
}
}
#include <stdint.h>
static int64_t i = 0;
void config_set_value(int64_t value) {
i = value;
}
void set_value(int64_t *foo) {
*foo = i;
}
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-Ccodegen-units=1",
"-Lauxiliary",
] And expresses between the two nightlies which bumped the LLVM version:
I'm moving this into a compiler codegen test and will close this issue when it is checked in. |
See rust-lang#115385 for more details.
Rollup merge of rust-lang#115591 - djkoloski:issue_115385, r=cuviper Add regression test for LLVM 17-rc3 miscompile Closes rust-lang#115385, see that issue for more details.
Running this code in release mode fails:
main.rs
:.cargo/config.toml
:Cargo.toml
When run with
cargo run --release
:This code passes under MIRI, so this is not the result of UB.
This does not repro on nightly, or even Fuchsia with the toolchain built upstream. We suspect that this may be because we setEdit: this turned out to be because we had-Cpanic=abort
on our toolchain, but we do have more differences from the upstream binaries.-Ccodegen-units=1
set in our build.We managed to bisect this in-tree down to #114048, which updated the LLVM submodule to 17.0.0. That, along with the nature of the bug, gives us confidence that this is likely a miscompile when using the
codegen-units
flag.This reproduces with the latest nightly:
as well as the nightly immediately after the LLVM upgrade:
The text was updated successfully, but these errors were encountered: