about summary refs log tree commit diff
path: root/library/coretests
diff options
context:
space:
mode:
Diffstat (limited to 'library/coretests')
-rw-r--r--library/coretests/tests/hint.rs36
1 files changed, 36 insertions, 0 deletions
diff --git a/library/coretests/tests/hint.rs b/library/coretests/tests/hint.rs
index 032bbc1dcc8..24de27b24b8 100644
--- a/library/coretests/tests/hint.rs
+++ b/library/coretests/tests/hint.rs
@@ -21,3 +21,39 @@ fn select_unpredictable_drop() {
     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);
+}