Skip to content

Commit

Permalink
Add some tests for #107975
Browse files Browse the repository at this point in the history
  • Loading branch information
GrigorenkoPV committed Jul 6, 2024
1 parent 3bec617 commit 2565349
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 0 deletions.
24 changes: 24 additions & 0 deletions tests/ui/codegen/equal-pointers-unequal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
See https://github.com/rust-lang/rust/issues/107975

Basically, if you have two pointers with the same address
but from two different allocations,
and then you do something with their addresses as integers,
the compiler may make some very strange assumptions during the compilation,
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()`.
24 changes: 24 additions & 0 deletions tests/ui/codegen/equal-pointers-unequal/as-cast/format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@ run-pass
//@ known-bug: #107975

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}"));
// But they are not equal.
assert_ne!(a, b);
// But they are the same hex number.
assert_eq!(format!("{a:x}"), format!("{b:x}"));
// But they are not equal.
assert_ne!(a, b);
}
25 changes: 25 additions & 0 deletions tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//@ run-pass
//@ known-bug: #107975

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?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//@ run-pass
//@ known-bug: #107975

#![feature(exposed_provenance)]

use std::ptr::addr_of;

fn main() {
let a: usize = {
let v = 0u8;
addr_of!(v).expose_provenance()
};
let b: usize = {
let v = 0u8;
addr_of!(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}"));
// But they are not equal.
assert_ne!(a, b);
// But they are the same hex number.
assert_eq!(format!("{a:x}"), format!("{b:x}"));
// But they are not equal.
assert_ne!(a, b);
}
30 changes: 30 additions & 0 deletions tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//@ run-pass
//@ known-bug: #107975

#![feature(exposed_provenance)]

use std::ptr::addr_of;

fn main() {
let a: usize = {
let v = 0u8;
addr_of!(v).expose_provenance()
};
let b: usize = {
let v = 0u8;
addr_of!(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?
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//@ run-pass
//@ known-bug: #107975

#![feature(strict_provenance)]

use std::ptr::addr_of;

fn main() {
let a: usize = {
let v = 0u8;
addr_of!(v).addr()
};
let b: usize = {
let v = 0u8;
addr_of!(v).addr()
};

// `a` and `b` are not equal.
assert_ne!(a, b);
// But they are the same number.
assert_eq!(format!("{a}"), format!("{b}"));
// But they are not equal.
assert_ne!(a, b);
// But they are the same hex number.
assert_eq!(format!("{a:x}"), format!("{b:x}"));
// But they are not equal.
assert_ne!(a, b);
}
29 changes: 29 additions & 0 deletions tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//@ run-pass
//@ known-bug: #107975

#![feature(strict_provenance)]

use std::ptr::addr_of;

fn main() {
let a: usize = {
let v = 0u8;
addr_of!(v).addr()
};
let b: usize = {
let v = 0u8;
addr_of!(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?
}

0 comments on commit 2565349

Please sign in to comment.