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

safe code can implement unreachable intrinsic #37088

Closed
oli-obk opened this issue Oct 11, 2016 · 2 comments
Closed

safe code can implement unreachable intrinsic #37088

oli-obk opened this issue Oct 11, 2016 · 2 comments

Comments

@oli-obk
Copy link
Contributor

oli-obk commented Oct 11, 2016

If you run the following piece of code in release mode, instead of going into an infinite loop (like in debug mode) the program terminates.

fn fermat() -> bool {
    const MAX: i32 = 1000;
    let (mut a, mut b, mut c) = (1, 1, 1);
    loop {
        if (a * a * a) == ((b * b * b) + (c * c * c)) {
            return true;
        };
        a += 1;
        if a > MAX {
            a = 1;
            b += 1;
        }
        if b > MAX {
            b = 1;
            c += 1;
        }
        if c > MAX {
            c = 1;
        }
    }
}

fn main() {
    if fermat() {
        println!("Fermat's Last Theorem has been disproved.");
    } else {
        println!("Fermat's Last Theorem has not been disproved.");
    }
}

Obviously this has been ripped off http://blog.regehr.org/archives/140 100% (it's an exact transcript from the C code shown there)

This is a "known" LLVM "bug". There is lots of discussion to what the right course of action is. One might say this is a convoluted example. But observe! The following program should not terminate after a rather trivial value range analysis:

fn f() -> bool {
    let mut a = 1;
    loop {
        if a == 2000 {
            return true;
        }
        a += 1;
        if a > 1000 {
            a = 1;
        }
    }
}

fn main() {
    assert!(f());
}

Still, the above program terminates in release mode, which is obviously riddiculous. It get's even crazier when you omit the return value:

fn f() {
    let mut a = 1;
    while a != 2000 {
        if a > 1000 {
            a = 1;
        }
    }
}

fn main() {
    f();
}

This function optimizes to the following LLVM-IR:

define internal void @_ZN8rust_out4main17hb497928495d48c40E() unnamed_addr #0 {
entry-block:
  unreachable
}

Now we can go have a party. The following code prints out the numbers from 0 to 99...

fn unreachable() {
    fn f() {
        while true {}
    }
    f();
}

fn main() {
    for i in 0..100 {
        match i {
            5 => unreachable(),
            other => println!("{}", other),
        }
    }
}

TLDR: LLVM removes side-effect free infinite loops that contain an unreachable loop abort.

@jonas-schievink
Copy link
Contributor

Duplicate of #18785 and/or #28728

@oli-obk
Copy link
Contributor Author

oli-obk commented Oct 11, 2016

indeed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants