diff --git a/tests/ui/codegen/equal-pointers-unequal/README.md b/tests/ui/codegen/equal-pointers-unequal/README.md new file mode 100644 index 0000000000000..343f9646a32cb --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/README.md @@ -0,0 +1,22 @@ +See https://github.com/rust-lang/rust/issues/107975 + +Basically, if you have two pointers with the same address but from two different allocations, +the compiler gets confused whether their addresses are equal or not, +resulting in some self-contradictory behavior of the compiled code. + +This folder contains some examples. +They all boil down to allocating a variable on the stack, taking its address, +getting rid of the variable, and then doing it all again. +This way we end up with two addresses stored in two `usize`s (`a` and `b`). +The addresses are (probably) equal but (definitely) come from two different allocations. +Logically, we would expect that exactly one of the following options holds true: +1. `a == b` +2. `a != b` +Sadly, the compiler does not always agree. + +Due to Rust having at least three meaningfully different ways +to get a variable's address as an `usize`, +each example is provided in three versions, each in the corresponding subfolder: +1. `./as-cast/` for `&v as *const _ as usize`, +2. `./strict-provenance/` for `addr_of!(v).addr()`, +2. `./exposed-provenance/` for `addr_of!(v).expose_provenance()`. diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs new file mode 100644 index 0000000000000..e2a00ce173d14 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs @@ -0,0 +1,21 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +fn main() { + let a: usize = { + let v = 0u8; + &v as *const _ as usize + }; + let b: usize = { + let v = 0u8; + &v as *const _ as usize + }; + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // And they are equal. + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs new file mode 100644 index 0000000000000..15434de50f76c --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs @@ -0,0 +1,22 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 + +fn f() -> usize { + let v = 0; + &v as *const _ as usize +} + +fn main() { + let a = f(); + let b = f(); + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // And they are equal. + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs new file mode 100644 index 0000000000000..d13fd4b63b306 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs @@ -0,0 +1,30 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 + +#[inline(never)] +fn cmp(a: usize, b: usize) -> bool { + a == b +} + +#[inline(always)] +fn cmp_in(a: usize, b: usize) -> bool { + a == b +} + +fn main() { + let a = { + let v = 0; + &v as *const _ as usize + }; + let b = { + let v = 0; + &v as *const _ as usize + }; + assert_eq!(format!("{}", a == b), "false"); + assert_eq!(format!("{}", cmp_in(a, b)), "false"); + assert_eq!(format!("{}", cmp(a, b)), "true"); + assert_eq!(a.to_string(), b.to_string()); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs new file mode 100644 index 0000000000000..9a1ace86e4db8 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs @@ -0,0 +1,30 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 + +#[inline(never)] +fn cmp(a: usize, b: usize) -> bool { + a == b +} + +#[inline(always)] +fn cmp_in(a: usize, b: usize) -> bool { + a == b +} + +fn main() { + let a = { + let v = 0; + &v as *const _ as usize + }; + let b = { + let v = 0; + &v as *const _ as usize + }; + assert_eq!(a.to_string(), b.to_string()); + assert_eq!(format!("{}", a == b), "true"); + assert_eq!(format!("{}", cmp_in(a, b)), "true"); + assert_eq!(format!("{}", cmp(a, b)), "true"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs new file mode 100644 index 0000000000000..f33a9e511b61a --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs @@ -0,0 +1,20 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 + +fn main() { + let a = { + let v = 0; + &v as *const _ as usize + }; + let b = { + let v = 0; + &v as *const _ as usize + }; + + assert_ne!(a, b); + println!("{a}"); // or b + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs new file mode 100644 index 0000000000000..eda83e999a528 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs @@ -0,0 +1,23 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 + +fn main() { + let a = { + let v = 0; + &v as *const _ as usize + }; + let b = { + let v = 0; + &v as *const _ as usize + }; + + assert_ne!(a, b); + assert_ne!(a, b); + let c = a; + assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "false true false"); + println!("{a} {b}"); + assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "true true true"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs new file mode 100644 index 0000000000000..97a875f15bc89 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs @@ -0,0 +1,63 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 + +use std::cell::{Ref, RefCell}; + +fn main() { + let a: usize = { + let v = 0u8; + &v as *const _ as usize + }; + let b: usize = { + let v = 0u8; + &v as *const _ as usize + }; + let i: usize = b - a; + + // A surprise tool that will help us later. + let arr = [ + RefCell::new(Some(Box::new(1u8))), + RefCell::new(None), + RefCell::new(None), + RefCell::new(None), + ]; + + // `i` is not 0 + assert_ne!(i, 0); + + // Let's borrow the `i`-th element. + // If `i` is out of bounds, indexing will panic. + let r: Ref>> = arr[i].borrow(); + + // If we got here, it means `i` was in bounds. + // Now, two options are possible: + // EITHER `i` is not 0 (as we have asserted above), + // so the unwrap will panic, because only the 0-th element is `Some` + // OR the assert lied, `i` *is* 0, and the `unwrap` will not panic. + let r: &Box = r.as_ref().unwrap(); + + // If we got here, it means `i` *was* actually 0. + // Let's ignore the fact that the assert has lied + // and try to take a mutable reference to the 0-th element. + // `borrow_mut` should panic, because we are sill holding on + // to a shared `Ref` for the same `RefCell`. + *arr[0].borrow_mut() = None; + + // But it doesn't panic! + // We have successfully replaced `Some(Box)` with `None`, + // while holding a shared reference to it. + // No unsafe involved. + + // The `Box` has been deallocated by now, so this is a dangling reference! + let r: &u8 = &*r; + println!("{:p}", r); + + // The following might segfault. Or it might not. + // Depends on the platform semantics + // and whatever happened to the pointed-to memory after deallocation. + // let u: u8 = *r; + // println!("{u}"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs new file mode 100644 index 0000000000000..d1aa95a9a569d --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs @@ -0,0 +1,28 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 + +fn main() { + let a: usize = { + let v = 0u8; + &v as *const _ as usize + }; + let b: usize = { + let v = 0u8; + &v as *const _ as usize + }; + + // So, are `a` and `b` equal? + + // Let's check their difference. + let i: usize = a - b; + // It's not zero, which means `a` and `b` are not equal. + assert_ne!(i, 0); + // But it looks like zero... + assert_eq!(i.to_string(), "0"); + // ...and now it *is* zero? + assert_eq!(i, 0); + // So `a` and `b` are equal after all? +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs new file mode 100644 index 0000000000000..0c9df7ecd7827 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs @@ -0,0 +1,25 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +#![feature(exposed_provenance)] + +use std::ptr; + +fn main() { + let a: usize = { + let v = 0u8; + ptr::from_ref(&v).expose_provenance() + }; + let b: usize = { + let v = 0u8; + ptr::from_ref(&v).expose_provenance() + }; + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // And they are equal. + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs new file mode 100644 index 0000000000000..b188b794d1fc7 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs @@ -0,0 +1,26 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 + +#![feature(exposed_provenance)] + +use std::ptr; + +fn f() -> usize { + let v = 0; + ptr::from_ref(&v).expose_provenance() +} + +fn main() { + let a = f(); + let b = f(); + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // And they are equal. + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs new file mode 100644 index 0000000000000..7f64e23b9c121 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs @@ -0,0 +1,34 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 + +#![feature(exposed_provenance)] + +use std::ptr; + +#[inline(never)] +fn cmp(a: usize, b: usize) -> bool { + a == b +} + +#[inline(always)] +fn cmp_in(a: usize, b: usize) -> bool { + a == b +} + +fn main() { + let a: usize = { + let v = 0; + ptr::from_ref(&v).expose_provenance() + }; + let b: usize = { + let v = 0; + ptr::from_ref(&v).expose_provenance() + }; + assert_eq!(format!("{}", a == b), "false"); + assert_eq!(format!("{}", cmp_in(a, b)), "false"); + assert_eq!(format!("{}", cmp(a, b)), "true"); + assert_eq!(a.to_string(), b.to_string()); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs new file mode 100644 index 0000000000000..3417296ce125a --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs @@ -0,0 +1,34 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 + +#![feature(exposed_provenance)] + +use std::ptr; + +#[inline(never)] +fn cmp(a: usize, b: usize) -> bool { + a == b +} + +#[inline(always)] +fn cmp_in(a: usize, b: usize) -> bool { + a == b +} + +fn main() { + let a: usize = { + let v = 0; + ptr::from_ref(&v).expose_provenance() + }; + let b: usize = { + let v = 0; + ptr::from_ref(&v).expose_provenance() + }; + assert_eq!(a.to_string(), b.to_string()); + assert_eq!(format!("{}", a == b), "true"); + assert_eq!(format!("{}", cmp_in(a, b)), "true"); + assert_eq!(format!("{}", cmp(a, b)), "true"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs new file mode 100644 index 0000000000000..e1e9e3f46b8ae --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs @@ -0,0 +1,24 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 + +#![feature(exposed_provenance)] + +use std::ptr; + +fn main() { + let a: usize = { + let v = 0; + ptr::from_ref(&v).expose_provenance() + }; + let b: usize = { + let v = 0; + ptr::from_ref(&v).expose_provenance() + }; + + assert_ne!(a, b); + println!("{a}"); // or b + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs new file mode 100644 index 0000000000000..8d581e8c9e93e --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs @@ -0,0 +1,27 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 + +#![feature(exposed_provenance)] + +use std::ptr; + +fn main() { + let a: usize = { + let v = 0; + ptr::from_ref(&v).expose_provenance() + }; + let b: usize = { + let v = 0; + ptr::from_ref(&v).expose_provenance() + }; + + assert_ne!(a, b); + assert_ne!(a, b); + let c = a; + assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "false true false"); + println!("{a} {b}"); + assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "true true true"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs new file mode 100644 index 0000000000000..506f114cd2a41 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs @@ -0,0 +1,68 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 + +#![feature(exposed_provenance)] + +use std::{ + cell::{Ref, RefCell}, + ptr, +}; + +fn main() { + let a: usize = { + let v = 0u8; + ptr::from_ref(&v).expose_provenance() + }; + let b: usize = { + let v = 0u8; + ptr::from_ref(&v).expose_provenance() + }; + let i: usize = b - a; + + // A surprise tool that will help us later. + let arr = [ + RefCell::new(Some(Box::new(1u8))), + RefCell::new(None), + RefCell::new(None), + RefCell::new(None), + ]; + + // `i` is not 0 + assert_ne!(i, 0); + + // Let's borrow the `i`-th element. + // If `i` is out of bounds, indexing will panic. + let r: Ref>> = arr[i].borrow(); + + // If we got here, it means `i` was in bounds. + // Now, two options are possible: + // EITHER `i` is not 0 (as we have asserted above), + // so the unwrap will panic, because only the 0-th element is `Some` + // OR the assert lied, `i` *is* 0, and the `unwrap` will not panic. + let r: &Box = r.as_ref().unwrap(); + + // If we got here, it means `i` *was* actually 0. + // Let's ignore the fact that the assert has lied + // and try to take a mutable reference to the 0-th element. + // `borrow_mut` should panic, because we are sill holding on + // to a shared `Ref` for the same `RefCell`. + *arr[0].borrow_mut() = None; + + // But it doesn't panic! + // We have successfully replaced `Some(Box)` with `None`, + // while holding a shared reference to it. + // No unsafe involved. + + // The `Box` has been deallocated by now, so this is a dangling reference! + let r: &u8 = &*r; + println!("{:p}", r); + + // The following might segfault. Or it might not. + // Depends on the platform semantics + // and whatever happened to the pointed-to memory after deallocation. + // let u: u8 = *r; + // println!("{u}"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs new file mode 100644 index 0000000000000..603db5e08f4af --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs @@ -0,0 +1,32 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 + +#![feature(exposed_provenance)] + +use std::ptr; + +fn main() { + let a: usize = { + let v = 0u8; + ptr::from_ref(&v).expose_provenance() + }; + let b: usize = { + let v = 0u8; + ptr::from_ref(&v).expose_provenance() + }; + + // So, are `a` and `b` equal? + + // Let's check their difference. + let i: usize = a - b; + // It's not zero, which means `a` and `b` are not equal. + assert_ne!(i, 0); + // But it looks like zero... + assert_eq!(i.to_string(), "0"); + // ...and now it *is* zero? + assert_eq!(i, 0); + // So `a` and `b` are equal after all? +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs new file mode 100644 index 0000000000000..0243c2bfe9511 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs @@ -0,0 +1,25 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +#![feature(strict_provenance)] + +use std::ptr; + +fn main() { + let a: usize = { + let v = 0u8; + ptr::from_ref(&v).addr() + }; + let b: usize = { + let v = 0u8; + ptr::from_ref(&v).addr() + }; + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // And they are equal. + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs new file mode 100644 index 0000000000000..29758036a21ed --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs @@ -0,0 +1,26 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 + +#![feature(strict_provenance)] + +use std::ptr; + +fn f() -> usize { + let v = 0; + ptr::from_ref(&v).addr() +} + +fn main() { + let a = f(); + let b = f(); + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // And they are equal. + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs new file mode 100644 index 0000000000000..11925261a6529 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs @@ -0,0 +1,34 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 + +#![feature(strict_provenance)] + +use std::ptr; + +#[inline(never)] +fn cmp(a: usize, b: usize) -> bool { + a == b +} + +#[inline(always)] +fn cmp_in(a: usize, b: usize) -> bool { + a == b +} + +fn main() { + let a: usize = { + let v = 0; + ptr::from_ref(&v).addr() + }; + let b: usize = { + let v = 0; + ptr::from_ref(&v).addr() + }; + assert_eq!(format!("{}", a == b), "false"); + assert_eq!(format!("{}", cmp_in(a, b)), "false"); + assert_eq!(format!("{}", cmp(a, b)), "true"); + assert_eq!(a.to_string(), b.to_string()); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs new file mode 100644 index 0000000000000..e628bb90faac3 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs @@ -0,0 +1,34 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1432161340 + +#![feature(strict_provenance)] + +use std::ptr; + +#[inline(never)] +fn cmp(a: usize, b: usize) -> bool { + a == b +} + +#[inline(always)] +fn cmp_in(a: usize, b: usize) -> bool { + a == b +} + +fn main() { + let a: usize = { + let v = 0; + ptr::from_ref(&v).addr() + }; + let b: usize = { + let v = 0; + ptr::from_ref(&v).addr() + }; + assert_eq!(a.to_string(), b.to_string()); + assert_eq!(format!("{}", a == b), "true"); + assert_eq!(format!("{}", cmp_in(a, b)), "true"); + assert_eq!(format!("{}", cmp(a, b)), "true"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs new file mode 100644 index 0000000000000..075e3475a32cc --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs @@ -0,0 +1,24 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 + +#![feature(strict_provenance)] + +use std::ptr; + +fn main() { + let a: usize = { + let v = 0; + ptr::from_ref(&v).addr() + }; + let b: usize = { + let v = 0; + ptr::from_ref(&v).addr() + }; + + assert_ne!(a, b); + println!("{a}"); // or b + assert_eq!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs new file mode 100644 index 0000000000000..6d7b6fa33e026 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs @@ -0,0 +1,27 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 + +#![feature(strict_provenance)] + +use std::ptr; + +fn main() { + let a: usize = { + let v = 0; + ptr::from_ref(&v).addr() + }; + let b: usize = { + let v = 0; + ptr::from_ref(&v).addr() + }; + + assert_ne!(a, b); + assert_ne!(a, b); + let c = a; + assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "false true false"); + println!("{a} {b}"); + assert_eq!(format!("{} {} {}", a == b, a == c, b == c), "true true true"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs new file mode 100644 index 0000000000000..67660d285a48a --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs @@ -0,0 +1,68 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 + +#![feature(strict_provenance)] + +use std::{ + cell::{Ref, RefCell}, + ptr, +}; + +fn main() { + let a: usize = { + let v = 0u8; + ptr::from_ref(&v).addr() + }; + let b: usize = { + let v = 0u8; + ptr::from_ref(&v).addr() + }; + let i: usize = b - a; + + // A surprise tool that will help us later. + let arr = [ + RefCell::new(Some(Box::new(1u8))), + RefCell::new(None), + RefCell::new(None), + RefCell::new(None), + ]; + + // `i` is not 0 + assert_ne!(i, 0); + + // Let's borrow the `i`-th element. + // If `i` is out of bounds, indexing will panic. + let r: Ref>> = arr[i].borrow(); + + // If we got here, it means `i` was in bounds. + // Now, two options are possible: + // EITHER `i` is not 0 (as we have asserted above), + // so the unwrap will panic, because only the 0-th element is `Some` + // OR the assert lied, `i` *is* 0, and the `unwrap` will not panic. + let r: &Box = r.as_ref().unwrap(); + + // If we got here, it means `i` *was* actually 0. + // Let's ignore the fact that the assert has lied + // and try to take a mutable reference to the 0-th element. + // `borrow_mut` should panic, because we are sill holding on + // to a shared `Ref` for the same `RefCell`. + *arr[0].borrow_mut() = None; + + // But it doesn't panic! + // We have successfully replaced `Some(Box)` with `None`, + // while holding a shared reference to it. + // No unsafe involved. + + // The `Box` has been deallocated by now, so this is a dangling reference! + let r: &u8 = &*r; + println!("{:p}", r); + + // The following might segfault. Or it might not. + // Depends on the platform semantics + // and whatever happened to the pointed-to memory after deallocation. + // let u: u8 = *r; + // println!("{u}"); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs new file mode 100644 index 0000000000000..a89310f993045 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs @@ -0,0 +1,32 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass + +// Derived from https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 + +#![feature(strict_provenance)] + +use std::ptr; + +fn main() { + let a: usize = { + let v = 0u8; + ptr::from_ref(&v).addr() + }; + let b: usize = { + let v = 0u8; + ptr::from_ref(&v).addr() + }; + + // So, are `a` and `b` equal? + + // Let's check their difference. + let i: usize = a - b; + // It's not zero, which means `a` and `b` are not equal. + assert_ne!(i, 0); + // But it looks like zero... + assert_eq!(i.to_string(), "0"); + // ...and now it *is* zero? + assert_eq!(i, 0); + // So `a` and `b` are equal after all? +}