Skip to content

Commit 2871d9b

Browse files
committed
Auto merge of rust-lang#127003 - GrigorenkoPV:107975, r=SparrowLii
Add a test for rust-lang#107975 The int is zero. But also not zero. This is so much fun. This is a part of rust-lang#105107. Initially I was going to just rebase rust-lang#108445, but quite a few things changed since then: * The [mcve](rust-lang#105787 (comment)) used for rust-lang#105787 got fixed.[^upd2] * You can't just `a ?= b` for rust-lang#107975 anymore. Now you have to `a-b ?= 0`. This is what this PR does. As an additional flex, it show that three ways of converting a pointer to its address have this issue: 1. `as usize` 2. `.expose_provenance()` 3. `.addr()` * rust-lang#108425 simply got fixed. Yay. As an aside, the naming for `addr_of!` is quite unfortunate in context of provenance APIs. Because `addr_of!` gives you a pointer, but what provenance APIs refer to as "address" is the `usize` value. Oh well. UPD1: GitHub is incapable of parsing rust-lang#107975 in the PR name, so let's add it here. [^upd2]: UPD2: [The other mcve](rust-lang#105787 (comment)) does not work anymore either, saying "this behavior recently changed as a result of a bug fix; see rust-lang#56105 for details."
2 parents cb12b52 + 14ae11f commit 2871d9b

37 files changed

+753
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
See https://github.com/rust-lang/rust/issues/107975
2+
3+
Basically, if you have two pointers with the same address but from two different allocations,
4+
the compiler gets confused whether their addresses are equal or not,
5+
resulting in some self-contradictory behavior of the compiled code.
6+
7+
This folder contains some examples.
8+
They all boil down to allocating a variable on the stack, taking its address,
9+
getting rid of the variable, and then doing it all again.
10+
This way we end up with two addresses stored in two `usize`s (`a` and `b`).
11+
The addresses are (probably) equal but (definitely) come from two different allocations.
12+
Logically, we would expect that exactly one of the following options holds true:
13+
1. `a == b`
14+
2. `a != b`
15+
Sadly, the compiler does not always agree.
16+
17+
Due to Rust having at least three meaningfully different ways
18+
to get a variable's address as an `usize`,
19+
each example is provided in three versions, each in the corresponding subfolder:
20+
1. `./as-cast/` for `&v as *const _ as usize`,
21+
2. `./strict-provenance/` for `addr_of!(v).addr()`,
22+
2. `./exposed-provenance/` for `addr_of!(v).expose_provenance()`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
5+
fn main() {
6+
let a: usize = {
7+
let v = 0u8;
8+
&v as *const _ as usize
9+
};
10+
let b: usize = {
11+
let v = 0u8;
12+
&v as *const _ as usize
13+
};
14+
15+
// `a` and `b` are not equal.
16+
assert_ne!(a, b);
17+
// But they are the same number.
18+
assert_eq!(format!("{a}"), format!("{b}"));
19+
// And they are equal.
20+
assert_eq!(a, b);
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
5+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908
6+
7+
fn f() -> usize {
8+
let v = 0;
9+
&v as *const _ as usize
10+
}
11+
12+
fn main() {
13+
let a = f();
14+
let b = f();
15+
16+
// `a` and `b` are not equal.
17+
assert_ne!(a, b);
18+
// But they are the same number.
19+
assert_eq!(format!("{a}"), format!("{b}"));
20+
// And they are equal.
21+
assert_eq!(a, b);
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
8+
9+
#[inline(never)]
10+
fn cmp(a: usize, b: usize) -> bool {
11+
a == b
12+
}
13+
14+
#[inline(always)]
15+
fn cmp_in(a: usize, b: usize) -> bool {
16+
a == b
17+
}
18+
19+
fn main() {
20+
let a = {
21+
let v = 0;
22+
&v as *const _ as usize
23+
};
24+
let b = {
25+
let v = 0;
26+
&v as *const _ as usize
27+
};
28+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
29+
assert_eq!(a.to_string(), b.to_string());
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<..> == <..> -> ==: false, cmp_in: false, cmp: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
8+
9+
#[inline(never)]
10+
fn cmp(a: usize, b: usize) -> bool {
11+
a == b
12+
}
13+
14+
#[inline(always)]
15+
fn cmp_in(a: usize, b: usize) -> bool {
16+
a == b
17+
}
18+
19+
fn main() {
20+
let a = {
21+
let v = 0;
22+
&v as *const _ as usize
23+
};
24+
let b = {
25+
let v = 0;
26+
&v as *const _ as usize
27+
};
28+
assert_eq!(a.to_string(), b.to_string());
29+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<..> == <..> -> ==: true, cmp_in: true, cmp: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
8+
9+
fn main() {
10+
let a = {
11+
let v = 0;
12+
&v as *const _ as usize
13+
};
14+
let b = {
15+
let v = 0;
16+
&v as *const _ as usize
17+
};
18+
19+
println!("{}", a == b); // prints false
20+
println!("{a}"); // or b
21+
println!("{}", a == b); // prints true
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
false
2+
<..>
3+
true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
8+
9+
fn main() {
10+
let a = {
11+
let v = 0;
12+
&v as *const _ as usize
13+
};
14+
let b = {
15+
let v = 0;
16+
&v as *const _ as usize
17+
};
18+
19+
println!("{}", a == b); // false
20+
println!("{}", a == b); // false
21+
let c = a;
22+
println!("{} {} {}", a == b, a == c, b == c); // false true false
23+
println!("{a} {b}");
24+
println!("{} {} {}", a == b, a == c, b == c); // true true true
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
false
2+
false
3+
false true false
4+
<..> <..>
5+
true true true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-fail
4+
//@ check-run-results
5+
6+
// This one should segfault.
7+
// I don't know a better way to check for segfault other than
8+
// check that it fails and that the output is empty.
9+
10+
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
11+
12+
use std::cell::RefCell;
13+
14+
fn main() {
15+
let a = {
16+
let v = 0u8;
17+
&v as *const _ as usize
18+
};
19+
let b = {
20+
let v = 0u8;
21+
&v as *const _ as usize
22+
};
23+
let i = b - a;
24+
let arr = [
25+
RefCell::new(Some(Box::new(1))),
26+
RefCell::new(None),
27+
RefCell::new(None),
28+
RefCell::new(None),
29+
];
30+
assert_ne!(i, 0);
31+
let r = arr[i].borrow();
32+
let r = r.as_ref().unwrap();
33+
*arr[0].borrow_mut() = None;
34+
println!("{}", *r);
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
5+
// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
6+
7+
fn main() {
8+
let a: usize = {
9+
let v = 0u8;
10+
&v as *const _ as usize
11+
};
12+
let b: usize = {
13+
let v = 0u8;
14+
&v as *const _ as usize
15+
};
16+
17+
// So, are `a` and `b` equal?
18+
19+
// Let's check their difference.
20+
let i: usize = a - b;
21+
// It's not zero, which means `a` and `b` are not equal.
22+
assert_ne!(i, 0);
23+
// But it looks like zero...
24+
assert_eq!(i.to_string(), "0");
25+
// ...and now it *is* zero?
26+
assert_eq!(i, 0);
27+
// So `a` and `b` are equal after all?
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
5+
#![feature(exposed_provenance)]
6+
7+
use std::ptr::addr_of;
8+
9+
fn main() {
10+
let a: usize = {
11+
let v = 0u8;
12+
addr_of!(v).expose_provenance()
13+
};
14+
let b: usize = {
15+
let v = 0u8;
16+
addr_of!(v).expose_provenance()
17+
};
18+
19+
// `a` and `b` are not equal.
20+
assert_ne!(a, b);
21+
// But they are the same number.
22+
assert_eq!(format!("{a}"), format!("{b}"));
23+
// And they are equal.
24+
assert_eq!(a, b);
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
5+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908
6+
7+
#![feature(exposed_provenance)]
8+
9+
use std::ptr::addr_of;
10+
11+
fn f() -> usize {
12+
let v = 0;
13+
addr_of!(v).expose_provenance()
14+
}
15+
16+
fn main() {
17+
let a = f();
18+
let b = f();
19+
20+
// `a` and `b` are not equal.
21+
assert_ne!(a, b);
22+
// But they are the same number.
23+
assert_eq!(format!("{a}"), format!("{b}"));
24+
// And they are equal.
25+
assert_eq!(a, b);
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
8+
9+
10+
#![feature(exposed_provenance)]
11+
12+
use std::ptr::addr_of;
13+
14+
#[inline(never)]
15+
fn cmp(a: usize, b: usize) -> bool {
16+
a == b
17+
}
18+
19+
#[inline(always)]
20+
fn cmp_in(a: usize, b: usize) -> bool {
21+
a == b
22+
}
23+
24+
fn main() {
25+
let a = {
26+
let v = 0;
27+
addr_of!(v).expose_provenance()
28+
};
29+
let b = {
30+
let v = 0;
31+
addr_of!(v).expose_provenance()
32+
};
33+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
34+
assert_eq!(a.to_string(), b.to_string());
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<..> == <..> -> ==: false, cmp_in: false, cmp: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
8+
9+
#![feature(exposed_provenance)]
10+
11+
use std::ptr::addr_of;
12+
13+
#[inline(never)]
14+
fn cmp(a: usize, b: usize) -> bool {
15+
a == b
16+
}
17+
18+
#[inline(always)]
19+
fn cmp_in(a: usize, b: usize) -> bool {
20+
a == b
21+
}
22+
23+
fn main() {
24+
let a = {
25+
let v = 0;
26+
addr_of!(v).expose_provenance()
27+
};
28+
let b = {
29+
let v = 0;
30+
addr_of!(v).expose_provenance()
31+
};
32+
assert_eq!(a.to_string(), b.to_string());
33+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<..> == <..> -> ==: true, cmp_in: true, cmp: true

0 commit comments

Comments
 (0)