Skip to content

Commit 91c6f8a

Browse files
committed
Add a bunch of tests for #107975
1 parent 8a8ad34 commit 91c6f8a

40 files changed

+877
-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,33 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// FIXME(#127914)
8+
//@ normalize-stdout-test: "uploaded .* waiting for result\n" -> ""
9+
10+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
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+
&v as *const _ as usize
26+
};
27+
let b = {
28+
let v = 0;
29+
&v as *const _ as usize
30+
};
31+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
32+
assert_eq!(a.to_string(), b.to_string());
33+
}
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+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// FIXME(#127914)
8+
//@ normalize-stdout-test: "uploaded .* waiting for result\n" -> ""
9+
10+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
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+
&v as *const _ as usize
26+
};
27+
let b = {
28+
let v = 0;
29+
&v as *const _ as usize
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
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,28 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// FIXME(#127914)
8+
//@ normalize-stdout-test: "uploaded .* waiting for result\n" -> ""
9+
10+
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499
11+
12+
fn main() {
13+
let a = {
14+
let v = 0;
15+
&v as *const _ as usize
16+
};
17+
let b = {
18+
let v = 0;
19+
&v as *const _ as usize
20+
};
21+
22+
println!("{}", a == b); // false
23+
println!("{}", a == b); // false
24+
let c = a;
25+
println!("{} {} {}", a == b, a == c, b == c); // false true false
26+
println!("{a} {b}");
27+
println!("{} {} {}", a == b, a == c, b == c); // true true true
28+
}
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,65 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "0x[\dabcdef]+" -> "0x<..>"
6+
7+
// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601
8+
9+
use std::cell::{Ref, RefCell};
10+
11+
fn main() {
12+
let a: usize = {
13+
let v = 0u8;
14+
&v as *const _ as usize
15+
};
16+
let b: usize = {
17+
let v = 0u8;
18+
&v as *const _ as usize
19+
};
20+
let i: usize = b - a;
21+
22+
// A surprise tool that will help us later.
23+
let arr = [
24+
RefCell::new(Some(Box::new(1u8))),
25+
RefCell::new(None),
26+
RefCell::new(None),
27+
RefCell::new(None),
28+
];
29+
30+
// `i` is not 0
31+
assert_ne!(i, 0);
32+
33+
// Let's borrow the `i`-th element.
34+
// If `i` is out of bounds, indexing will panic.
35+
let r: Ref<Option<Box<u8>>> = arr[i].borrow();
36+
37+
// If we got here, it means `i` was in bounds.
38+
// Now, two options are possible:
39+
// EITHER `i` is not 0 (as we have asserted above),
40+
// so the unwrap will panic, because only the 0-th element is `Some`
41+
// OR the assert lied, `i` *is* 0, and the `unwrap` will not panic.
42+
let r: &Box<u8> = r.as_ref().unwrap();
43+
44+
// If we got here, it means `i` *was* actually 0.
45+
// Let's ignore the fact that the assert has lied
46+
// and try to take a mutable reference to the 0-th element.
47+
// `borrow_mut` should panic, because we are sill holding on
48+
// to a shared `Ref` for the same `RefCell`.
49+
*arr[0].borrow_mut() = None;
50+
51+
// But it doesn't panic!
52+
// We have successfully replaced `Some(Box)` with `None`,
53+
// while holding a shared reference to it.
54+
// No unsafe involved.
55+
56+
// The `Box` has been deallocated by now, so this is a dangling reference!
57+
let r: &u8 = &*r;
58+
println!("{:p}", r);
59+
60+
// The following might segfault. Or it might not.
61+
// Depends on the platform semantics
62+
// and whatever happened to the pointed-to memory after deallocation.
63+
// let u: u8 = *r;
64+
// println!("{u}");
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0x<..>
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;
8+
9+
fn main() {
10+
let a: usize = {
11+
let v = 0u8;
12+
ptr::from_ref(&v).expose_provenance()
13+
};
14+
let b: usize = {
15+
let v = 0u8;
16+
ptr::from_ref(&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;
10+
11+
fn f() -> usize {
12+
let v = 0;
13+
ptr::from_ref(&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,37 @@
1+
//@ known-bug: #107975
2+
//@ compile-flags: -Copt-level=2
3+
//@ run-pass
4+
//@ check-run-results
5+
//@ normalize-stdout-test: "\d+" -> "<..>"
6+
7+
// FIXME(#127914)
8+
//@ normalize-stdout-test: "uploaded .* waiting for result\n" -> ""
9+
10+
// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340
11+
12+
#![feature(exposed_provenance)]
13+
14+
use std::ptr;
15+
16+
#[inline(never)]
17+
fn cmp(a: usize, b: usize) -> bool {
18+
a == b
19+
}
20+
21+
#[inline(always)]
22+
fn cmp_in(a: usize, b: usize) -> bool {
23+
a == b
24+
}
25+
26+
fn main() {
27+
let a: usize = {
28+
let v = 0;
29+
ptr::from_ref(&v).expose_provenance()
30+
};
31+
let b: usize = {
32+
let v = 0;
33+
ptr::from_ref(&v).expose_provenance()
34+
};
35+
println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b));
36+
assert_eq!(a.to_string(), b.to_string());
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<..> == <..> -> ==: false, cmp_in: false, cmp: true

0 commit comments

Comments
 (0)