Skip to content
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

incorrect integer comparison in release build #116913

Closed
adfernandes opened this issue Oct 19, 2023 · 9 comments
Closed

incorrect integer comparison in release build #116913

adfernandes opened this issue Oct 19, 2023 · 9 comments
Labels
C-bug Category: This is a bug.

Comments

@adfernandes
Copy link

The following code is well-formed, as far as I can tell:

fn main() {
    let a = {
        let v = 0;
        &v as *const _ as usize
    };
    let b = {
        let v = 0;
        &v as *const _ as usize
    };
    println!("{a:?} == {b:?} evaluates to {}", a==b);
    println!("{a:?} == {b:?} evaluates to {}", a==b);
}

For debug builds, we see the expected output, where the two println! macros output the same string:

$ cargo run 
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/rust-bug-addr-scope`
140734029226756 == 140734029226772 evaluates to false
140734029226756 == 140734029226772 evaluates to false

However, for release builds, the second line no longer matches the first:

$ cargo run --release
    Finished release [optimized] target(s) in 0.00s
     Running `target/release/rust-bug-addr-scope`
140735084703752 == 140735084703752 evaluates to false
140735084703752 == 140735084703752 evaluates to true

Rust Playground Link

Since both a and b are integer constants, it should not matter that the variable pointed to goes out of scope.

I would expect that the release build gives identical output to the debug output.

Note that both evaluates to true and evaluates to false are acceptable.

However, the release build is implying that two identical integers can mis-compare, in that the boolean a==b is not constant!

Meta

Occurs on both x86_64-unknown-linux-gnu and aarch64-unknown-linux-gnu.

rustc --version --verbose:

cargo 1.73.0 (9c4383fb5 2023-08-26)
release: 1.73.0
commit-hash: 9c4383fb55986096b414d98125421ab87b5fd642
commit-date: 2023-08-26
host: x86_64-unknown-linux-gnu
libgit2: 1.6.4 (sys:0.17.2 vendored)
libcurl: 8.2.1-DEV (sys:0.4.65+curl-8.2.1 vendored ssl:OpenSSL/1.1.1u)
ssl: OpenSSL 1.1.1u  30 May 2023
os: Ubuntu 22.04 (jammy) [64-bit]

and

cargo 1.73.0 (9c4383fb5 2023-08-26)
release: 1.73.0
commit-hash: 9c4383fb55986096b414d98125421ab87b5fd642
commit-date: 2023-08-26
host: aarch64-unknown-linux-gnu
libgit2: 1.6.4 (sys:0.17.2 vendored)
libcurl: 8.2.1-DEV (sys:0.4.65+curl-8.2.1 vendored ssl:OpenSSL/1.1.1u)
ssl: OpenSSL 1.1.1u  30 May 2023
os: Ubuntu 20.04 (focal) [64-bit]
@adfernandes adfernandes added the C-bug Category: This is a bug. label Oct 19, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Oct 19, 2023
@fmease
Copy link
Member

fmease commented Oct 19, 2023

Potential duplicate of #107975.

@Noratrieb
Copy link
Member

closing as duplicate

@Noratrieb Noratrieb closed this as not planned Won't fix, can't repro, duplicate, stale Oct 19, 2023
@DoubleHyphen
Copy link

Out of curiosity, what thought process led you to this bug?

@adfernandes
Copy link
Author

adfernandes commented Oct 19, 2023

A colleague who dislikes rust sent it to me as an example of "memory unsafety" in rust, without realizing that it was a compiler bug.

I will admit, it took me discussing it with several friends before I started to realize it was surely a compiler bug, esp with respect to the optimizer.

(In a past life I had many a shouting match, err, I mean "spirited discussion" with people who didn't realize just how dangerous things like -ffast-math really are! I think the std::hint::black_box in the original bug throws a lot of people off, because it's ... well, blackbox-ish!)

Anyhow

From a C / C++ perspective, this bug doesn't worry me too much because the C repro' in upstream LLVM would be a relatively uncommon construction in C.

However, writing an idiom that triggers this bug would not be uncommon in embedded rust, which is my primary interest!

(NB I will probably cross-post this bug to the Ferrocene Project, because they are working towards "Safety Crititcal" embedded rust, where the compiler doesn't need to be perfect, but defects need to be known!)

@Noratrieb
Copy link
Member

ferrocene is aware of all I-unsound issues already

@adfernandes
Copy link
Author

Ah! Was hoping that would be the case… cheers!

@fmease fmease removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Oct 20, 2023
@DoubleHyphen
Copy link

A colleague who dislikes rust sent it to me as an example of "memory unsafety" in rust, without realizing that it was a compiler bug.

I'll admit that I find this curious, as this bug is rather niche. For a person who “dislikes Rust”, your colleague is oddly knowledgeable.

@adfernandes
Copy link
Author

For a person who “dislikes Rust”, your colleague is oddly knowledgeable.

Yeah, that's an interesting story. My colleague is a phenomenal C++ coder... the type of person who not only knows the standard, but understands the reasoning behind the standard. So... very bright and thoughtful.

Unfortunately, they had the misfortune of working somewhere that decided to cargo-cult Rust for "safety". You know the attitude, I suspect: "Build it in Rust, and it will be safe and secure!" Said colleague then had a very miserable time as the company shoehorned really bad software and really bad practices into Rust, believing that The One True Language would save them from themselves.

This appears to have left them very sour on Rust.

For what it's worth, I have several friends and colleagues that work at companies that have experimented (poorly) with Rust. The common experience seems to be that they end up with the unholy combination of shoehorned-in C-like constructs and drag-down, knock-em-down fights with the borrow checker! The worst of both worlds!

I kind-of understand this, because I enjoyed writing Java for many years before getting introduced to (now lampoon-able) "Enterprise Java". These days I don't care how great Java is in theory... I'd rather jump off of a cliff than touch it. "Once burned, twice shy" and all that.

So what I suspect is happening is that many of my corporate-software-developer friends are doing the equivalent of "trying to learn Fortran by writing a full-stack modern web app", having a miserable experience, and then reverting via Stockholm Syndrome to PHP, where they are comfortable.

Make sense?

And yes, I know that people have written a web framework in Fortran... 😆

@DoubleHyphen
Copy link

DoubleHyphen commented Feb 8, 2024

For a person who “dislikes Rust”, your colleague is oddly knowledgeable.

Yeah, that's an interesting story. My colleague is a phenomenal C++ coder... the type of person who not only knows the standard, but understands the reasoning behind the standard. So... very bright and thoughtful.

Unfortunately, they had the misfortune of working somewhere that decided to cargo-cult Rust for "safety". You know the attitude, I suspect: "Build it in Rust, and it will be safe and secure!" Said colleague then had a very miserable time as the company shoehorned really bad software and really bad practices into Rust, believing that The One True Language would save them from themselves.

This appears to have left them very sour on Rust.

For what it's worth, I have several friends and colleagues that work at companies that have experimented (poorly) with Rust. The common experience seems to be that they end up with the unholy combination of shoehorned-in C-like constructs and drag-down, knock-em-down fights with the borrow checker! The worst of both worlds!

I kind-of understand this, because I enjoyed writing Java for many years before getting introduced to (now lampoon-able) "Enterprise Java". These days I don't care how great Java is in theory... I'd rather jump off of a cliff than touch it. "Once burned, twice shy" and all that.

So what I suspect is happening is that many of my corporate-software-developer friends are doing the equivalent of "trying to learn Fortran by writing a full-stack modern web app", having a miserable experience, and then reverting via Stockholm Syndrome to PHP, where they are comfortable.

Make sense?

And yes, I know that people have written a web framework in Fortran... 😆

This does make sense. Still, I saw the C reproduction to which you linked, and… it appears oddly verbose, somehow. This is all that's needed to reproduce the bug:

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uintptr_t a;
    uintptr_t b;

    {
        int v[2] = {0, 0};
        a = (uintptr_t)&(v[0]);
    }

    {
        int v[2] = {0, 0};
        b = (uintptr_t)&(v[0]);
    }

    printf("%ld ==/^ %ld is %d, %ld\n", a, b, a == b, a ^ b);
    a ^= 1, b ^= 1;
    printf("%ld ==/^ %ld is %d, %ld\n", a, b, a == b, a ^ b);

    return 0;
}

As long as optimisations are enabled, this bug reproduces in both C and C++, in both gcc and clang. With that in mind, how likely is it that you'd hit this bug in embedded Rust but not in embedded C/C++?

As for the rest you mentioned… admittedly, the worst thing one can do in Rust is to try to use it to implement other languages' solutions for those other languages' problems. It is staggering how many problems that can cause—and the worst part is that it can happen from various languages of departure, from C to PHP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

5 participants