Description
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.