Skip to content

Commit 88a37a2

Browse files
committed
test/ui/consts: Add tests for const ptr offsets
Signed-off-by: Joe Richey <joerichey@google.com>
1 parent 9b3dfd8 commit 88a37a2

File tree

3 files changed

+291
-0
lines changed

3 files changed

+291
-0
lines changed

src/test/ui/consts/offset.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// run-pass
2+
#![feature(const_ptr_offset)]
3+
#![feature(const_ptr_offset_from)]
4+
#![feature(ptr_offset_from)]
5+
use std::ptr;
6+
7+
#[repr(C)]
8+
struct Struct {
9+
a: u32,
10+
b: u32,
11+
c: u32,
12+
}
13+
static S: Struct = Struct { a: 0, b: 0, c: 0 };
14+
15+
// For these tests we use offset_from to check that two pointers are equal.
16+
// Rust doesn't currently support comparing pointers in const fn.
17+
18+
static OFFSET_NO_CHANGE: bool = unsafe {
19+
let p1 = &S.b as *const u32;
20+
let p2 = p1.offset(2).offset(-2);
21+
p1.offset_from(p2) == 0
22+
};
23+
static OFFSET_MIDDLE: bool = unsafe {
24+
let p1 = (&S.a as *const u32).offset(1);
25+
let p2 = (&S.c as *const u32).offset(-1);
26+
p1.offset_from(p2) == 0
27+
};
28+
// Pointing to the end of the allocation is OK
29+
static OFFSET_END: bool = unsafe {
30+
let p1 = (&S.a as *const u32).offset(3);
31+
let p2 = (&S.c as *const u32).offset(1);
32+
p1.offset_from(p2) == 0
33+
};
34+
// Casting though a differently sized type is OK
35+
static OFFSET_U8_PTR: bool = unsafe {
36+
let p1 = (&S.a as *const u32 as *const u8).offset(5);
37+
let p2 = (&S.c as *const u32 as *const u8).offset(-3);
38+
p1.offset_from(p2) == 0
39+
};
40+
// Any offset with a ZST does nothing
41+
const OFFSET_ZST: bool = unsafe {
42+
let pz = &() as *const ();
43+
// offset_from can't work with ZSTs, so cast to u8 ptr
44+
let p1 = pz.offset(5) as *const u8;
45+
let p2 = pz.offset(isize::MIN) as *const u8;
46+
p1.offset_from(p2) == 0
47+
};
48+
const OFFSET_ZERO: bool = unsafe {
49+
let p = [0u8; 0].as_ptr();
50+
p.offset(0).offset_from(p) == 0
51+
};
52+
const OFFSET_ONE: bool = unsafe {
53+
let p = &42u32 as *const u32;
54+
p.offset(1).offset_from(p) == 1
55+
};
56+
const OFFSET_DANGLING: bool = unsafe {
57+
let p = ptr::NonNull::<u8>::dangling().as_ptr();
58+
p.offset(0).offset_from(p) == 0
59+
};
60+
const OFFSET_UNALIGNED: bool = unsafe {
61+
let arr = [0u8; 32];
62+
let p1 = arr.as_ptr();
63+
let p2 = (p1.offset(2) as *const u32).offset(1);
64+
(p2 as *const u8).offset_from(p1) == 6
65+
};
66+
67+
const WRAP_OFFSET_NO_CHANGE: bool = unsafe {
68+
let p1 = &42u32 as *const u32;
69+
let p2 = p1.wrapping_offset(1000).wrapping_offset(-1000);
70+
let p3 = p1.wrapping_offset(-1000).wrapping_offset(1000);
71+
(p1.offset_from(p2) == 0) & (p1.offset_from(p3) == 0)
72+
};
73+
const WRAP_ADDRESS_SPACE: bool = unsafe {
74+
let p1 = &42u8 as *const u8;
75+
let p2 = p1.wrapping_offset(isize::MIN).wrapping_offset(isize::MIN);
76+
p1.offset_from(p2) == 0
77+
};
78+
// Wrap on the count*size_of::<T>() calculation.
79+
const WRAP_SIZE_OF: bool = unsafe {
80+
// Make sure that if p1 moves backwards, we are still in range
81+
let arr = [0u32; 2];
82+
let p = &arr[1] as *const u32;
83+
// With wrapping arithmetic, isize::MAX * 4 == -4
84+
let wrapped = p.wrapping_offset(isize::MAX);
85+
let backward = p.wrapping_offset(-1);
86+
wrapped.offset_from(backward) == 0
87+
};
88+
const WRAP_INTEGER_POINTER: bool = unsafe {
89+
let p1 = (0x42 as *const u32).wrapping_offset(4);
90+
let p2 = 0x52 as *const u32;
91+
p1.offset_from(p2) == 0
92+
};
93+
const WRAP_NULL: bool = unsafe {
94+
let p1 = ptr::null::<u32>().wrapping_offset(1);
95+
let p2 = 0x4 as *const u32;
96+
p1.offset_from(p2) == 0
97+
};
98+
99+
fn main() {
100+
assert!(OFFSET_NO_CHANGE);
101+
assert!(OFFSET_MIDDLE);
102+
assert!(OFFSET_END);
103+
assert!(OFFSET_U8_PTR);
104+
assert!(OFFSET_ZST);
105+
assert!(OFFSET_ZERO);
106+
assert!(OFFSET_ONE);
107+
assert!(OFFSET_DANGLING);
108+
assert!(OFFSET_UNALIGNED);
109+
110+
assert!(WRAP_OFFSET_NO_CHANGE);
111+
assert!(WRAP_ADDRESS_SPACE);
112+
assert!(WRAP_SIZE_OF);
113+
assert!(WRAP_INTEGER_POINTER);
114+
assert!(WRAP_NULL);
115+
}

src/test/ui/consts/offset_ub.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// ignore-tidy-linelength
2+
#![feature(const_ptr_offset)]
3+
use std::ptr;
4+
5+
// normalize-stderr-test "alloc\d+" -> "allocN"
6+
7+
pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~NOTE
8+
pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~NOTE
9+
pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~NOTE
10+
11+
pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~NOTE
12+
pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~NOTE
13+
pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~NOTE
14+
pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~NOTE
15+
16+
pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~NOTE
17+
pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) }; //~NOTE
18+
19+
// Right now, a zero offset from null is UB
20+
pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) }; //~NOTE
21+
22+
fn main() {}

src/test/ui/consts/offset_ub.stderr

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
error: any use of this value will cause an error
2+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
3+
|
4+
LL | intrinsics::offset(self, count)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| overflowing in-bounds pointer arithmetic
8+
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
9+
| inside `BEFORE_START` at $DIR/offset_ub.rs:7:46
10+
|
11+
::: $DIR/offset_ub.rs:7:1
12+
|
13+
LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) };
14+
| ------------------------------------------------------------------------------
15+
|
16+
= note: `#[deny(const_err)]` on by default
17+
18+
error: any use of this value will cause an error
19+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
20+
|
21+
LL | intrinsics::offset(self, count)
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
| |
24+
| inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1
25+
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
26+
| inside `AFTER_END` at $DIR/offset_ub.rs:8:43
27+
|
28+
::: $DIR/offset_ub.rs:8:1
29+
|
30+
LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) };
31+
| --------------------------------------------------------------------------
32+
33+
error: any use of this value will cause an error
34+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
35+
|
36+
LL | intrinsics::offset(self, count)
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
| |
39+
| inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100
40+
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
41+
| inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45
42+
|
43+
::: $DIR/offset_ub.rs:9:1
44+
|
45+
LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) };
46+
| ------------------------------------------------------------------------------
47+
48+
error: any use of this value will cause an error
49+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
50+
|
51+
LL | intrinsics::offset(self, count)
52+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
53+
| |
54+
| inbounds pointer arithmetic: overflow computing offset
55+
| inside `std::ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
56+
| inside `OVERFLOW` at $DIR/offset_ub.rs:11:43
57+
|
58+
::: $DIR/offset_ub.rs:11:1
59+
|
60+
LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) };
61+
| ----------------------------------------------------------------------------------
62+
63+
error: any use of this value will cause an error
64+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
65+
|
66+
LL | intrinsics::offset(self, count)
67+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68+
| |
69+
| inbounds pointer arithmetic: overflow computing offset
70+
| inside `std::ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
71+
| inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44
72+
|
73+
::: $DIR/offset_ub.rs:12:1
74+
|
75+
LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) };
76+
| -----------------------------------------------------------------------------------
77+
78+
error: any use of this value will cause an error
79+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
80+
|
81+
LL | intrinsics::offset(self, count)
82+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
83+
| |
84+
| overflowing in-bounds pointer arithmetic
85+
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
86+
| inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56
87+
|
88+
::: $DIR/offset_ub.rs:13:1
89+
|
90+
LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) };
91+
| ---------------------------------------------------------------------------------------------
92+
93+
error: any use of this value will cause an error
94+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
95+
|
96+
LL | intrinsics::offset(self, count)
97+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
98+
| |
99+
| overflowing in-bounds pointer arithmetic
100+
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
101+
| inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57
102+
|
103+
::: $DIR/offset_ub.rs:14:1
104+
|
105+
LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) };
106+
| --------------------------------------------------------------------------------------
107+
108+
error: any use of this value will cause an error
109+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
110+
|
111+
LL | intrinsics::offset(self, count)
112+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
113+
| |
114+
| inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0
115+
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
116+
| inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50
117+
|
118+
::: $DIR/offset_ub.rs:16:1
119+
|
120+
LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) };
121+
| -------------------------------------------------------------------------------
122+
123+
error: any use of this value will cause an error
124+
--> $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL
125+
|
126+
LL | intrinsics::offset(self, count) as *mut T
127+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
128+
| |
129+
| unable to turn bytes into a pointer
130+
| inside `std::ptr::mut_ptr::<impl *mut u8>::offset` at $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL
131+
| inside `DANGLING` at $DIR/offset_ub.rs:17:42
132+
|
133+
::: $DIR/offset_ub.rs:17:1
134+
|
135+
LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) };
136+
| ---------------------------------------------------------------------------------------------
137+
138+
error: any use of this value will cause an error
139+
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
140+
|
141+
LL | intrinsics::offset(self, count)
142+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
143+
| |
144+
| inbounds test failed: 0x0 is not a valid pointer
145+
| inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
146+
| inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50
147+
|
148+
::: $DIR/offset_ub.rs:20:1
149+
|
150+
LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) };
151+
| -------------------------------------------------------------------------------
152+
153+
error: aborting due to 10 previous errors
154+

0 commit comments

Comments
 (0)