about summary refs log tree commit diff
path: root/library/coretests/tests/hint.rs
blob: 24de27b24b8027c7d3f69012b201baec4554de7e (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
#[test]
fn select_unpredictable_drop() {
    use core::cell::Cell;
    struct X<'a>(&'a Cell<bool>);
    impl Drop for X<'_> {
        fn drop(&mut self) {
            self.0.set(true);
        }
    }

    let a_dropped = Cell::new(false);
    let b_dropped = Cell::new(false);
    let a = X(&a_dropped);
    let b = X(&b_dropped);
    assert!(!a_dropped.get());
    assert!(!b_dropped.get());
    let selected = core::hint::select_unpredictable(core::hint::black_box(true), a, b);
    assert!(!a_dropped.get());
    assert!(b_dropped.get());
    drop(selected);
    assert!(a_dropped.get());
    assert!(b_dropped.get());
}

#[test]
#[should_panic = "message canary"]
fn select_unpredictable_drop_on_panic() {
    use core::cell::Cell;

    struct X<'a> {
        cell: &'a Cell<u16>,
        expect: u16,
        write: u16,
    }

    impl Drop for X<'_> {
        fn drop(&mut self) {
            let value = self.cell.get();
            self.cell.set(self.write);
            assert_eq!(value, self.expect, "message canary");
        }
    }

    let cell = Cell::new(0);

    // Trigger a double-panic if the selected cell was not dropped during panic.
    let _armed = X { cell: &cell, expect: 0xdead, write: 0 };
    let selected = X { cell: &cell, write: 0xdead, expect: 1 };
    let unselected = X { cell: &cell, write: 1, expect: 0xff };

    // The correct drop order is:
    //
    // 1. `unselected` drops, writes 1, and panics as 0 != 0xff
    // 2. `selected` drops during unwind, writes 0xdead and does not panic as 1 == 1
    // 3. `armed` drops during unwind, writes 0 and does not panic as 0xdead == 0xdead
    //
    // If `selected` is not dropped, `armed` panics as 1 != 0xdead
    let _unreachable = core::hint::select_unpredictable(true, selected, unselected);
}