about summary refs log tree commit diff
path: root/tests/ui/consts/offset_from_ub.rs
blob: ccbe591f97e81d6ac896219788a351c44ffb90bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes"
//@ dont-require-annotations: NOTE

#![feature(core_intrinsics)]

use std::intrinsics::{ptr_offset_from, ptr_offset_from_unsigned};
use std::ptr;

#[repr(C)]
struct Struct {
    data: u8,
    field: u8,
}

pub const DIFFERENT_ALLOC: usize = {
    let uninit = std::mem::MaybeUninit::<Struct>::uninit();
    let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
    let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
    let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
    let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) };
    //~^ ERROR not both derived from the same allocation
    offset as usize
};

pub const NOT_PTR: usize = {
    unsafe { (42 as *const u8).offset_from(&5u8) as usize }
    //~^ ERROR not both derived from the same allocation
};

pub const NOT_MULTIPLE_OF_SIZE: isize = {
    let data = [5u8, 6, 7];
    let base_ptr = data.as_ptr();
    let field_ptr = &data[1] as *const u8 as *const u16;
    unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) }
    //~^ ERROR 1_isize cannot be divided by 2_isize without remainder
};

pub const DIFFERENT_INT: isize = {
    // offset_from with two different integers: like DIFFERENT_ALLOC
    let ptr1 = 8 as *const u8;
    let ptr2 = 16 as *const u8;
    unsafe { ptr_offset_from(ptr2, ptr1) }
    //~^ ERROR not both derived from the same allocation
};

const OUT_OF_BOUNDS_1: isize = {
    let start_ptr = &4 as *const _ as *const u8;
    let length = 10;
    let end_ptr = (start_ptr).wrapping_add(length);
    // First ptr is out of bounds
    unsafe { ptr_offset_from(end_ptr, start_ptr) }
    //~^ ERROR the memory range between them is not in-bounds of an allocation
};

const OUT_OF_BOUNDS_2: isize = {
    let start_ptr = &4 as *const _ as *const u8;
    let length = 10;
    let end_ptr = (start_ptr).wrapping_add(length);
    // Second ptr is out of bounds
    unsafe { ptr_offset_from(start_ptr, end_ptr) }
    //~^ ERROR the memory range between them is not in-bounds of an allocation
};

pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
    let uninit = std::mem::MaybeUninit::<Struct>::uninit();
    let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
    let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
    let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
    unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }
    //~^ ERROR not both derived from the same allocation
};

pub const TOO_FAR_APART1: isize = {
    let ptr1 = &0u8 as *const u8;
    let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
    unsafe { ptr_offset_from(ptr2, ptr1) }
    //~^ ERROR too far ahead
};
pub const TOO_FAR_APART2: isize = {
    let ptr1 = &0u8 as *const u8;
    let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
    unsafe { ptr_offset_from(ptr1, ptr2) }
    //~^ ERROR too far before
};
pub const TOO_FAR_APART3: isize = {
    let ptr1 = &0u8 as *const u8;
    let ptr2 = ptr1.wrapping_offset(isize::MIN);
    // The result of this would be `isize::MIN`, which *does* fit in an `isize`, but its
    // absolute value does not. (Also anyway there cannot be an allocation of that size.)
    unsafe { ptr_offset_from(ptr1, ptr2) }
    //~^ ERROR too far before
};

const WRONG_ORDER_UNSIGNED: usize = {
    let a = ['a', 'b', 'c'];
    let p = a.as_ptr();
    unsafe { ptr_offset_from_unsigned(p, p.add(2)) }
    //~^ ERROR first pointer has smaller offset than second: 0 < 8
};
pub const TOO_FAR_APART_UNSIGNED: usize = {
    let ptr1 = &0u8 as *const u8;
    let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
    // This would fit into a `usize` but we still don't allow it.
    unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR too far ahead
};

// These do NOT complain that pointers are too far apart; they pass that check (to then fail the
// next one).
pub const OFFSET_VERY_FAR1: isize = {
    let ptr1 = ptr::null::<u8>();
    let ptr2 = ptr1.wrapping_offset(isize::MAX);
    unsafe { ptr2.offset_from(ptr1) }
    //~^ ERROR called on two different pointers that are not both derived from the same allocation
};
pub const OFFSET_VERY_FAR2: isize = {
    let ptr1 = ptr::null::<u8>();
    let ptr2 = ptr1.wrapping_offset(isize::MAX);
    unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
    //~^ ERROR ptr_offset_from` called when first pointer is too far before second
};

// If the pointers are the same, OOB/null/UAF is fine.
pub const OFFSET_FROM_NULL_SAME: isize = {
    let ptr = 0 as *const u8;
    unsafe { ptr_offset_from(ptr, ptr) }
};
const OUT_OF_BOUNDS_SAME: isize = {
    let start_ptr = &4 as *const _ as *const u8;
    let length = 10;
    let end_ptr = (start_ptr).wrapping_add(length);
    unsafe { ptr_offset_from(end_ptr, end_ptr) }
};
const UAF_SAME: isize = {
    let uaf_ptr = {
        let x = 0;
        &x as *const i32
    };
    unsafe { ptr_offset_from(uaf_ptr, uaf_ptr) }
};

fn main() {}