about summary refs log tree commit diff
path: root/src/tools/miri/tests/pass/pointers.rs
blob: 280a815abc4303f86ee032dd10e5eb0905880b10 (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
142
143
144
//@compile-flags: -Zmiri-permissive-provenance
#![feature(ptr_metadata, const_raw_ptr_comparison)]
#![allow(ambiguous_wide_pointer_comparisons)]

use std::mem::{self, transmute};
use std::ptr;

fn one_line_ref() -> i16 {
    *&1
}

fn basic_ref() -> i16 {
    let x = &1;
    *x
}

fn basic_ref_mut() -> i16 {
    let x = &mut 1;
    *x += 2;
    *x
}

fn basic_ref_mut_var() -> i16 {
    let mut a = 1;
    {
        let x = &mut a;
        *x += 2;
    }
    a
}

fn tuple_ref_mut() -> (i8, i8) {
    let mut t = (10, 20);
    {
        let x = &mut t.1;
        *x += 2;
    }
    t
}

fn match_ref_mut() -> i8 {
    let mut t = (20, 22);
    {
        let opt = Some(&mut t);
        match opt {
            Some(&mut (ref mut x, ref mut y)) => *x += *y,
            None => {}
        }
    }
    t.0
}

fn dangling_pointer() -> *const i32 {
    let b = Box::new((42, 42)); // make it bigger than the alignment, so that there is some "room" after this pointer
    &b.0 as *const i32
}

fn wide_ptr_ops() {
    let a: *const dyn Send = &1 as &dyn Send;
    let b: *const dyn Send = &1 as &dyn Send;
    let _val = a == b;
    let _val = a != b;
    let _val = a < b;
    let _val = a <= b;
    let _val = a > b;
    let _val = a >= b;

    let a: *const [u8] = unsafe { transmute((1usize, 1usize)) };
    let b: *const [u8] = unsafe { transmute((1usize, 2usize)) };
    // confirmed with rustc.
    assert!(!(a == b));
    assert!(a != b);
    assert!(a <= b);
    assert!(a < b);
    assert!(!(a >= b));
    assert!(!(a > b));
}

fn metadata_vtable() {
    let p = &0i32 as &dyn std::fmt::Debug;
    let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _);
    assert_eq!(meta.size_of(), mem::size_of::<i32>());
    assert_eq!(meta.align_of(), mem::align_of::<i32>());

    type T = [i32; 16];
    let p = &T::default() as &dyn std::fmt::Debug;
    let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _);
    assert_eq!(meta.size_of(), mem::size_of::<T>());
    assert_eq!(meta.align_of(), mem::align_of::<T>());
}

fn main() {
    assert_eq!(one_line_ref(), 1);
    assert_eq!(basic_ref(), 1);
    assert_eq!(basic_ref_mut(), 3);
    assert_eq!(basic_ref_mut_var(), 3);
    assert_eq!(tuple_ref_mut(), (10, 22));
    assert_eq!(match_ref_mut(), 42);

    // Compare even dangling pointers with NULL, and with others in the same allocation, including
    // out-of-bounds.
    assert!(dangling_pointer() != std::ptr::null());
    assert!(match dangling_pointer() as usize {
        0 => false,
        _ => true,
    });
    let dangling = dangling_pointer();
    assert!(dangling == dangling);
    assert!(dangling.wrapping_add(1) != dangling);
    assert!(dangling.wrapping_sub(1) != dangling);

    // Compare pointer with BIG integers
    let dangling = dangling as usize;
    assert!(dangling != usize::MAX);
    assert!(dangling != usize::MAX - 1);
    assert!(dangling != usize::MAX - 2);
    assert!(dangling != usize::MAX - 3); // this is even 4-aligned, but it still cannot be equal because of the extra "room" after this pointer
    assert_eq!((usize::MAX - 3) % 4, 0); // just to be sure we got this right

    // Compare pointer with unaligned integers
    assert!(dangling != 1usize);
    assert!(dangling != 2usize);
    assert!(dangling != 3usize);
    // 4 is a possible choice! So we cannot compare with that.
    assert!(dangling != 5usize);
    assert!(dangling != 6usize);
    assert!(dangling != 7usize);

    // Using inequality to do the comparison.
    assert!(dangling > 0);
    assert!(dangling > 1);
    assert!(dangling > 2);
    assert!(dangling > 3);
    assert!(dangling >= 4);

    // CTFE-specific equality tests, need to also work at runtime.
    let addr = &13 as *const i32;
    let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1);
    assert_eq!(addr.guaranteed_eq(addr2 as *const _), Some(true));
    assert_eq!(addr.guaranteed_ne(0x100 as *const _), Some(true));

    wide_ptr_ops();
    metadata_vtable();
}