Skip to content

Commit 8024fd6

Browse files
committed
Add ui tests for slice::from_{ptr_range,raw_parts}
1 parent 80cbeb0 commit 8024fd6

File tree

3 files changed

+481
-0
lines changed

3 files changed

+481
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// run-pass
2+
#![feature(
3+
const_slice_from_raw_parts,
4+
slice_from_ptr_range,
5+
slice_from_ptr_range_const,
6+
pointer_byte_offsets,
7+
const_pointer_byte_offsets
8+
)]
9+
use std::{
10+
mem::MaybeUninit,
11+
ptr,
12+
slice::{from_ptr_range, from_raw_parts},
13+
};
14+
15+
// Dangling is ok, as long as it's either for ZST reads or for no reads
16+
pub static S0: &[u32] = unsafe { from_raw_parts(dangling(), 0) };
17+
pub static S1: &[()] = unsafe { from_raw_parts(dangling(), 3) };
18+
19+
// References are always valid of reads of a single element (basically `slice::from_ref`)
20+
pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 1) };
21+
pub static S3: &[MaybeUninit<&u32>] = unsafe { from_raw_parts(&D1, 1) };
22+
23+
// Reinterpreting data is fine, as long as layouts match
24+
pub static S4: &[u8] = unsafe { from_raw_parts((&D0) as *const _ as _, 3) };
25+
// This is only valid because D1 has uninitialized bytes, if it was an initialized pointer,
26+
// that would reinterpret pointers as integers which is UB in CTFE.
27+
pub static S5: &[MaybeUninit<u8>] = unsafe { from_raw_parts((&D1) as *const _ as _, 2) };
28+
// Even though u32 and [bool; 4] have different layouts, D0 has a value that
29+
// is valid as [bool; 4], so this is not UB (it's basically a transmute)
30+
pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
31+
32+
// Structs are considered single allocated objects,
33+
// as long as you don't reinterpret padding as initialized
34+
// data everything is ok.
35+
pub static S7: &[u16] = unsafe {
36+
let ptr = (&D2 as *const Struct as *const u16).byte_add(4);
37+
38+
from_raw_parts(ptr, 3)
39+
};
40+
pub static S8: &[MaybeUninit<u16>] = unsafe {
41+
let ptr = &D2 as *const Struct as *const MaybeUninit<u16>;
42+
43+
from_raw_parts(ptr, 6)
44+
};
45+
46+
pub static R0: &[u32] = unsafe { from_ptr_range(dangling()..dangling()) };
47+
// from_ptr_range panics on zst
48+
//pub static R1: &[()] = unsafe { from_ptr_range(dangling(), dangling().byte_add(3)) };
49+
pub static R2: &[u32] = unsafe {
50+
let ptr = &D0 as *const u32;
51+
from_ptr_range(ptr..ptr.add(1))
52+
};
53+
pub static R3: &[MaybeUninit<&u32>] = unsafe {
54+
let ptr = &D1 as *const MaybeUninit<&u32>;
55+
from_ptr_range(ptr..ptr.add(1))
56+
};
57+
pub static R4: &[u8] = unsafe {
58+
let ptr = &D0 as *const u32 as *const u8;
59+
from_ptr_range(ptr..ptr.add(3))
60+
};
61+
pub static R5: &[MaybeUninit<u8>] = unsafe {
62+
let ptr = &D1 as *const MaybeUninit<&u32> as *const MaybeUninit<u8>;
63+
from_ptr_range(ptr..ptr.add(2))
64+
};
65+
pub static R6: &[bool] = unsafe {
66+
let ptr = &D0 as *const u32 as *const bool;
67+
from_ptr_range(ptr..ptr.add(4))
68+
};
69+
pub static R7: &[u16] = unsafe {
70+
let d2 = &D2;
71+
let l = &d2.b as *const u32 as *const u16;
72+
let r = &d2.d as *const u8 as *const u16;
73+
74+
from_ptr_range(l..r)
75+
};
76+
pub static R8: &[MaybeUninit<u16>] = unsafe {
77+
let d2 = &D2;
78+
let l = d2 as *const Struct as *const MaybeUninit<u16>;
79+
let r = &d2.d as *const u8 as *const MaybeUninit<u16>;
80+
81+
from_ptr_range(l..r)
82+
};
83+
84+
// Using valid slice is always valid
85+
pub static R9: &[u32] = unsafe { from_ptr_range(R0.as_ptr_range()) };
86+
pub static R10: &[u32] = unsafe { from_ptr_range(R2.as_ptr_range()) };
87+
88+
const D0: u32 = (1 << 16) | 1;
89+
const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
90+
const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
91+
92+
const fn dangling<T>() -> *const T {
93+
ptr::NonNull::dangling().as_ptr() as _
94+
}
95+
96+
#[repr(C)]
97+
struct Struct {
98+
a: u8,
99+
// _pad: [MaybeUninit<u8>; 3]
100+
b: u32,
101+
c: u16,
102+
d: u8,
103+
// _pad: [MaybeUninit<u8>; 1]
104+
}
105+
106+
fn main() {}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#![feature(
2+
const_slice_from_raw_parts,
3+
slice_from_ptr_range,
4+
slice_from_ptr_range_const,
5+
pointer_byte_offsets,
6+
const_pointer_byte_offsets
7+
)]
8+
use std::{
9+
mem::{size_of, MaybeUninit},
10+
ptr,
11+
slice::{from_ptr_range, from_raw_parts},
12+
};
13+
14+
// Null is never valid for reads
15+
pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
16+
pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
17+
18+
// Out of bounds
19+
pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
20+
21+
// Reading uninitialized data
22+
pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; //~ ERROR: it is undefined behavior to use this value
23+
// Reinterpret pointers as integers (UB in CTFE.)
24+
pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; //~ ERROR: it is undefined behavior to use this value
25+
// Layout mismatch
26+
pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; //~ ERROR: it is undefined behavior to use this value
27+
28+
// Reading padding is not ok
29+
pub static S7: &[u16] = unsafe {
30+
//~^ ERROR: it is undefined behavior to use this value
31+
let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
32+
33+
from_raw_parts(ptr, 4)
34+
};
35+
36+
// Unaligned read
37+
pub static S8: &[u64] = unsafe {
38+
let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
39+
40+
from_raw_parts(ptr, 1)
41+
};
42+
43+
pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
44+
pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
45+
pub static R2: &[u32] = unsafe {
46+
let ptr = &D0 as *const u32;
47+
from_ptr_range(ptr..ptr.add(2))
48+
};
49+
pub static R4: &[u8] = unsafe {
50+
//~^ ERROR: it is undefined behavior to use this value
51+
let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8;
52+
from_ptr_range(ptr..ptr.add(1))
53+
};
54+
pub static R5: &[u8] = unsafe {
55+
//~^ ERROR: it is undefined behavior to use this value
56+
let ptr = &D3 as *const &u32;
57+
from_ptr_range(ptr.cast()..ptr.add(1).cast())
58+
};
59+
pub static R6: &[bool] = unsafe {
60+
//~^ ERROR: it is undefined behavior to use this value
61+
let ptr = &D0 as *const u32 as *const bool;
62+
from_ptr_range(ptr..ptr.add(4))
63+
};
64+
pub static R7: &[u16] = unsafe {
65+
//~^ ERROR: it is undefined behavior to use this value
66+
let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
67+
from_ptr_range(ptr..ptr.add(4))
68+
};
69+
pub static R8: &[u64] = unsafe {
70+
let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
71+
from_ptr_range(ptr..ptr.add(1))
72+
};
73+
74+
// This is sneaky: &D0 and &D0 point to different objects
75+
// (even if at runtime they have the same address)
76+
pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
77+
pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
78+
79+
const D0: u32 = 0x11;
80+
const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
81+
const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
82+
const D3: &u32 = &42;
83+
const D4: [u32; 2] = [17, 42];
84+
85+
#[repr(C)]
86+
struct Struct {
87+
a: u8,
88+
// _pad: [MaybeUninit<u8>; 3]
89+
b: u32,
90+
c: u16,
91+
d: u8,
92+
// _pad: [MaybeUninit<u8>; 1]
93+
}
94+
95+
fn main() {}

0 commit comments

Comments
 (0)