Skip to content

Commit 6364ce8

Browse files
committed
Auto merge of #127003 - GrigorenkoPV:107975, r=SparrowLii
Add a test for #107975 The int is zero. But also not zero. This is so much fun. This is a part of #105107. Initially I was going to just rebase #108445, but quite a few things changed since then: * The [mcve](#105787 (comment)) used for #105787 got fixed.[^upd2] * You can't just `a ?= b` for #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()` * #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 #107975 in the PR name, so let's add it here. [^upd2]: UPD2: [The other mcve](#105787 (comment)) does not work anymore either, saying "this behavior recently changed as a result of a bug fix; see #56105 for details."
2 parents cae4a84 + 562aaa4 commit 6364ce8

37 files changed

+732
-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,20 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
4+
fn main() {
5+
let a: usize = {
6+
let v = 0u8;
7+
&v as *const _ as usize
8+
};
9+
let b: usize = {
10+
let v = 0u8;
11+
&v as *const _ as usize
12+
};
13+
14+
// `a` and `b` are not equal.
15+
assert_ne!(a, b);
16+
// But they are the same number.
17+
assert_eq!(format!("{a}"), format!("{b}"));
18+
// And they are equal.
19+
assert_eq!(a, b);
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
4+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908
5+
6+
fn f() -> usize {
7+
let v = 0;
8+
&v as *const _ as usize
9+
}
10+
11+
fn main() {
12+
let a = f();
13+
let b = f();
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,29 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
//@ check-run-results
4+
//@ normalize-stdout-test: "\d+" -> "<..>"
5+
6+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
7+
8+
#[inline(never)]
9+
fn cmp(a: usize, b: usize) -> bool {
10+
a == b
11+
}
12+
13+
#[inline(always)]
14+
fn cmp_in(a: usize, b: usize) -> bool {
15+
a == b
16+
}
17+
18+
fn main() {
19+
let a = {
20+
let v = 0;
21+
&v as *const _ as usize
22+
};
23+
let b = {
24+
let v = 0;
25+
&v as *const _ as usize
26+
};
27+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
28+
assert_eq!(a.to_string(), b.to_string());
29+
}
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,29 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
//@ check-run-results
4+
//@ normalize-stdout-test: "\d+" -> "<..>"
5+
6+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
7+
8+
#[inline(never)]
9+
fn cmp(a: usize, b: usize) -> bool {
10+
a == b
11+
}
12+
13+
#[inline(always)]
14+
fn cmp_in(a: usize, b: usize) -> bool {
15+
a == b
16+
}
17+
18+
fn main() {
19+
let a = {
20+
let v = 0;
21+
&v as *const _ as usize
22+
};
23+
let b = {
24+
let v = 0;
25+
&v as *const _ as usize
26+
};
27+
assert_eq!(a.to_string(), b.to_string());
28+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
29+
}
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,21 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
//@ check-run-results
4+
//@ normalize-stdout-test: "\d+" -> "<..>"
5+
6+
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
7+
8+
fn main() {
9+
let a = {
10+
let v = 0;
11+
&v as *const _ as usize
12+
};
13+
let b = {
14+
let v = 0;
15+
&v as *const _ as usize
16+
};
17+
18+
println!("{}", a == b); // prints false
19+
println!("{a}"); // or b
20+
println!("{}", a == b); // prints true
21+
}
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,24 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
//@ check-run-results
4+
//@ normalize-stdout-test: "\d+" -> "<..>"
5+
6+
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
7+
8+
fn main() {
9+
let a = {
10+
let v = 0;
11+
&v as *const _ as usize
12+
};
13+
let b = {
14+
let v = 0;
15+
&v as *const _ as usize
16+
};
17+
18+
println!("{}", a == b); // false
19+
println!("{}", a == b); // false
20+
let c = a;
21+
println!("{} {} {}", a == b, a == c, b == c); // false true false
22+
println!("{a} {b}");
23+
println!("{} {} {}", a == b, a == c, b == c); // true true true
24+
}
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+
//@ run-fail
3+
//@ check-run-results
4+
//@ compile-flags: -Copt-level=3
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,27 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
4+
// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
5+
6+
fn main() {
7+
let a: usize = {
8+
let v = 0u8;
9+
&v as *const _ as usize
10+
};
11+
let b: usize = {
12+
let v = 0u8;
13+
&v as *const _ as usize
14+
};
15+
16+
// So, are `a` and `b` equal?
17+
18+
// Let's check their difference.
19+
let i: usize = a - b;
20+
// It's not zero, which means `a` and `b` are not equal.
21+
assert_ne!(i, 0);
22+
// But it looks like zero...
23+
assert_eq!(i.to_string(), "0");
24+
// ...and now it *is* zero?
25+
assert_eq!(i, 0);
26+
// So `a` and `b` are equal after all?
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
4+
#![feature(exposed_provenance)]
5+
6+
use std::ptr::addr_of;
7+
8+
fn main() {
9+
let a: usize = {
10+
let v = 0u8;
11+
addr_of!(v).expose_provenance()
12+
};
13+
let b: usize = {
14+
let v = 0u8;
15+
addr_of!(v).expose_provenance()
16+
};
17+
18+
// `a` and `b` are not equal.
19+
assert_ne!(a, b);
20+
// But they are the same number.
21+
assert_eq!(format!("{a}"), format!("{b}"));
22+
// And they are equal.
23+
assert_eq!(a, b);
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
4+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908
5+
6+
#![feature(exposed_provenance)]
7+
8+
use std::ptr::addr_of;
9+
10+
fn f() -> usize {
11+
let v = 0;
12+
addr_of!(v).expose_provenance()
13+
}
14+
15+
fn main() {
16+
let a = f();
17+
let b = f();
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,34 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
//@ check-run-results
4+
//@ normalize-stdout-test: "\d+" -> "<..>"
5+
6+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
7+
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+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
33+
assert_eq!(a.to_string(), b.to_string());
34+
}
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,33 @@
1+
//@ known-bug: #107975
2+
//@ run-pass
3+
//@ check-run-results
4+
//@ normalize-stdout-test: "\d+" -> "<..>"
5+
6+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
7+
8+
#![feature(exposed_provenance)]
9+
10+
use std::ptr::addr_of;
11+
12+
#[inline(never)]
13+
fn cmp(a: usize, b: usize) -> bool {
14+
a == b
15+
}
16+
17+
#[inline(always)]
18+
fn cmp_in(a: usize, b: usize) -> bool {
19+
a == b
20+
}
21+
22+
fn main() {
23+
let a = {
24+
let v = 0;
25+
addr_of!(v).expose_provenance()
26+
};
27+
let b = {
28+
let v = 0;
29+
addr_of!(v).expose_provenance()
30+
};
31+
assert_eq!(a.to_string(), b.to_string());
32+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<..> == <..> -> ==: true, cmp_in: true, cmp: true

0 commit comments

Comments
 (0)