summaryrefslogtreecommitdiff
path: root/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
blob: 9e604f9abb83a535d1b60909a7a62721d8077ef7 (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
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
use std::ptr;

// Just to make sure that casting a ref to raw, to int and back to raw
// and only then using it works. This rules out ideas like "do escape-to-raw lazily";
// after casting to int and back, we lost the tag that could have let us do that.
fn ref_raw_int_raw() {
    let mut x = 3;
    let xref = &mut x;
    let xraw = xref as *mut i32 as usize as *mut i32;
    assert_eq!(unsafe { *xraw }, 3);
}

/// Ensure that we do not just pick the topmost possible item on int2ptr casts.
fn example(variant: bool) {
    unsafe {
        fn not_so_innocent(x: &mut u32) -> usize {
            let x_raw4 = x as *mut u32;
            x_raw4.expose_addr()
        }

        let mut c = 42u32;

        let x_unique1 = &mut c;
        // stack: [..., Unique(1)]

        let x_raw2 = x_unique1 as *mut u32;
        let x_raw2_addr = x_raw2.expose_addr();
        // stack: [..., Unique(1), SharedRW(2)]

        let x_unique3 = &mut *x_raw2;
        // stack: [.., Unique(1), SharedRW(2), Unique(3)]

        assert_eq!(not_so_innocent(x_unique3), x_raw2_addr);
        // stack: [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)]

        // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags).
        // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers).
        // And indeed if `variant == true` it is the only possible choice.
        // But if `variant == false` then 2 is the only possible choice!
        let x_wildcard = ptr::from_exposed_addr_mut::<i32>(x_raw2_addr);

        if variant {
            // If we picked 2, this will invalidate 3.
            *x_wildcard = 10;
            // Now we use 3. Only possible if above we picked 4.
            *x_unique3 = 12;
        } else {
            // This invalidates tag 4.
            *x_unique3 = 10;
            // Now try to write with the "guessed" tag; it must be 2.
            *x_wildcard = 12;
        }
    }
}

fn test() {
    unsafe {
        let root = &mut 42;
        let root_raw = root as *mut i32;
        let addr1 = root_raw as usize;
        let child = &mut *root_raw;
        let child_raw = child as *mut i32;
        let addr2 = child_raw as usize;
        assert_eq!(addr1, addr2);
        // First use child.
        *(addr2 as *mut i32) -= 2; // picks child_raw
        *child -= 2;
        // Then use root.
        *(addr1 as *mut i32) += 2; // picks root_raw
        *root += 2;
        // Value should be unchanged.
        assert_eq!(*root, 42);
    }
}

fn main() {
    ref_raw_int_raw();
    example(false);
    example(true);
    test();
}