about summary refs log tree commit diff
path: root/library/alloc/tests
diff options
context:
space:
mode:
authordylni <46035563+dylni@users.noreply.github.com>2021-01-18 22:14:38 -0500
committerdylni <46035563+dylni@users.noreply.github.com>2021-01-18 22:14:38 -0500
commitb96063cf4757eb698611b57e9032da2b74c8c789 (patch)
tree7461d147a687279685cd5fa870577887b25955c6 /library/alloc/tests
parentd98d2f57d9b98325ff075c343d2c7695b66dfa7d (diff)
Fix soundness issue for `replace_range` and `range`
Diffstat (limited to 'library/alloc/tests')
-rw-r--r--library/alloc/tests/string.rs50
1 files changed, 50 insertions, 0 deletions
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
index b28694186b6..f3d74e0514d 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloc/tests/string.rs
@@ -1,7 +1,11 @@
 use std::borrow::Cow;
+use std::cell::Cell;
 use std::collections::TryReserveError::*;
+use std::ops::Bound;
 use std::ops::Bound::*;
+use std::ops::RangeBounds;
 use std::panic;
+use std::str;
 
 pub trait IntoCow<'a, B: ?Sized>
 where
@@ -562,6 +566,52 @@ fn test_replace_range_unbounded() {
 }
 
 #[test]
+fn test_replace_range_evil_start_bound() {
+    struct EvilRange(Cell<bool>);
+
+    impl RangeBounds<usize> for EvilRange {
+        fn start_bound(&self) -> Bound<&usize> {
+            Bound::Included(if self.0.get() {
+                &1
+            } else {
+                self.0.set(true);
+                &0
+            })
+        }
+        fn end_bound(&self) -> Bound<&usize> {
+            Bound::Unbounded
+        }
+    }
+
+    let mut s = String::from("🦀");
+    s.replace_range(EvilRange(Cell::new(false)), "");
+    assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
+}
+
+#[test]
+fn test_replace_range_evil_end_bound() {
+    struct EvilRange(Cell<bool>);
+
+    impl RangeBounds<usize> for EvilRange {
+        fn start_bound(&self) -> Bound<&usize> {
+            Bound::Included(&0)
+        }
+        fn end_bound(&self) -> Bound<&usize> {
+            Bound::Excluded(if self.0.get() {
+                &3
+            } else {
+                self.0.set(true);
+                &4
+            })
+        }
+    }
+
+    let mut s = String::from("🦀");
+    s.replace_range(EvilRange(Cell::new(false)), "");
+    assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
+}
+
+#[test]
 fn test_extend_ref() {
     let mut a = "foo".to_string();
     a.extend(&['b', 'a', 'r']);