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..2544923f033b6 --- /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 +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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 + }; + println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b)); + assert_eq!(a.to_string(), b.to_string()); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.run.stdout b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.run.stdout new file mode 100644 index 0000000000000..bf061737348e5 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.run.stdout @@ -0,0 +1 @@ +<..> == <..> -> ==: false, cmp_in: false, cmp: true 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..5d441fd5c555a --- /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 +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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()); + println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b)); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.run.stdout b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.run.stdout new file mode 100644 index 0000000000000..581a9c6efd61d --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.run.stdout @@ -0,0 +1 @@ +<..> == <..> -> ==: true, cmp_in: true, cmp: 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..6ee17ae0dffbc --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs @@ -0,0 +1,22 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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 + }; + + println!("{}", a == b); // prints false + println!("{a}"); // or b + println!("{}", a == b); // prints true +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/print.run.stdout b/tests/ui/codegen/equal-pointers-unequal/as-cast/print.run.stdout new file mode 100644 index 0000000000000..e9997f6521e95 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/print.run.stdout @@ -0,0 +1,3 @@ +false +<..> +true 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..1a6cea9ff5e7a --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs @@ -0,0 +1,25 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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 + }; + + println!("{}", a == b); // false + println!("{}", a == b); // false + let c = a; + println!("{} {} {}", a == b, a == c, b == c); // false true false + println!("{a} {b}"); + println!("{} {} {}", a == b, a == c, b == c); // true true true +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.run.stdout b/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.run.stdout new file mode 100644 index 0000000000000..03b7976944f4b --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/print3.run.stdout @@ -0,0 +1,5 @@ +false +false +false true false +<..> <..> +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..2723943278285 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs @@ -0,0 +1,65 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "0x[\dabcdef]+" -> "0x<..>" + +// 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/segfault.run.stdout b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.run.stdout new file mode 100644 index 0000000000000..29fb458fa2f0c --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.run.stdout @@ -0,0 +1 @@ +0x<..> 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..02ac80e1f88a5 --- /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 +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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() + }; + println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b)); + assert_eq!(a.to_string(), b.to_string()); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.run.stdout b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.run.stdout new file mode 100644 index 0000000000000..bf061737348e5 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.run.stdout @@ -0,0 +1 @@ +<..> == <..> -> ==: false, cmp_in: false, cmp: true 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..f77a355715596 --- /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 +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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()); + println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b)); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.run.stdout b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.run.stdout new file mode 100644 index 0000000000000..581a9c6efd61d --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.run.stdout @@ -0,0 +1 @@ +<..> == <..> -> ==: true, cmp_in: true, cmp: 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..5947b291d0d67 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs @@ -0,0 +1,26 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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() + }; + + println!("{}", a == b); // prints false + println!("{a}"); // or b + println!("{}", a == b); // prints true +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.run.stdout b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.run.stdout new file mode 100644 index 0000000000000..e9997f6521e95 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.run.stdout @@ -0,0 +1,3 @@ +false +<..> +true 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..fb9e346b7609f --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs @@ -0,0 +1,29 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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() + }; + + println!("{}", a == b); // false + println!("{}", a == b); // false + let c = a; + println!("{} {} {}", a == b, a == c, b == c); // false true false + println!("{a} {b}"); + println!("{} {} {}", a == b, a == c, b == c); // true true true +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.run.stdout b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.run.stdout new file mode 100644 index 0000000000000..03b7976944f4b --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.run.stdout @@ -0,0 +1,5 @@ +false +false +false true false +<..> <..> +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..ad32e3737096b --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs @@ -0,0 +1,70 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "0x[\dabcdef]+" -> "0x<..>" + +// 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/segfault.run.stdout b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.run.stdout new file mode 100644 index 0000000000000..29fb458fa2f0c --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.run.stdout @@ -0,0 +1 @@ +0x<..> 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..8364678fc7d0b --- /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 +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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() + }; + println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b)); + assert_eq!(a.to_string(), b.to_string()); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.run.stdout b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.run.stdout new file mode 100644 index 0000000000000..bf061737348e5 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.run.stdout @@ -0,0 +1 @@ +<..> == <..> -> ==: false, cmp_in: false, cmp: true 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..e9c5c2976f277 --- /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 +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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()); + println!("{a:?} == {b:?} -> ==: {}, cmp_in: {}, cmp: {}", a == b, cmp_in(a, b), cmp(a, b)); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.run.stdout b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.run.stdout new file mode 100644 index 0000000000000..581a9c6efd61d --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.run.stdout @@ -0,0 +1 @@ +<..> == <..> -> ==: true, cmp_in: true, cmp: 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..4b2e3613acf18 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs @@ -0,0 +1,26 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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() + }; + + println!("{}", a == b); // prints false + println!("{a}"); // or b + println!("{}", a == b); // prints true +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.run.stdout b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.run.stdout new file mode 100644 index 0000000000000..e9997f6521e95 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.run.stdout @@ -0,0 +1,3 @@ +false +<..> +true 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..cb0e103e8646b --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs @@ -0,0 +1,29 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "\d+" -> "<..>" + +// 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() + }; + + println!("{}", a == b); // false + println!("{}", a == b); // false + let c = a; + println!("{} {} {}", a == b, a == c, b == c); // false true false + println!("{a} {b}"); + println!("{} {} {}", a == b, a == c, b == c); // true true true +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.run.stdout b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.run.stdout new file mode 100644 index 0000000000000..03b7976944f4b --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.run.stdout @@ -0,0 +1,5 @@ +false +false +false true false +<..> <..> +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..a8e54e5dd3e9c --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs @@ -0,0 +1,70 @@ +//@ known-bug: #107975 +//@ compile-flags: -Copt-level=2 +//@ run-pass +//@ check-run-results +//@ normalize-stdout-test: "0x[\dabcdef]+" -> "0x<..>" + +// 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/segfault.run.stdout b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.run.stdout new file mode 100644 index 0000000000000..29fb458fa2f0c --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.run.stdout @@ -0,0 +1 @@ +0x<..> 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? +}