diff options
| author | Jonas Schievink <jonasschievink@gmail.com> | 2020-10-29 17:05:28 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-29 17:05:28 +0100 |
| commit | 48c4afbf9c29880dd946067d1c9aee1e7f75834a (patch) | |
| tree | 4edb3ac88fd5324a1b070600afced7d02ac4134c | |
| parent | a01e5f8c0dcf27462f93a174b179c0595eab3e43 (diff) | |
| parent | 1f6f917f73a4372f098e9b19560b5945be145dc3 (diff) | |
| download | rust-48c4afbf9c29880dd946067d1c9aee1e7f75834a.tar.gz rust-48c4afbf9c29880dd946067d1c9aee1e7f75834a.zip | |
Rollup merge of #78499 - SkiFire13:fix-string-retain, r=m-ou-se
Prevent String::retain from creating non-utf8 strings when abusing panic Fixes #78498 The idea is the same as `Vec::drain`, set the len to 0 so that nobody can observe the broken invariant if it escapes the function (in this case if `f` panics)
| -rw-r--r-- | library/alloc/src/string.rs | 10 | ||||
| -rw-r--r-- | library/alloc/tests/string.rs | 15 |
2 files changed, 21 insertions, 4 deletions
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 72ed036637d..ce216e5336e 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1235,6 +1235,10 @@ impl String { let mut del_bytes = 0; let mut idx = 0; + unsafe { + self.vec.set_len(0); + } + while idx < len { let ch = unsafe { self.get_unchecked(idx..len).chars().next().unwrap() }; let ch_len = ch.len_utf8(); @@ -1255,10 +1259,8 @@ impl String { idx += ch_len; } - if del_bytes > 0 { - unsafe { - self.vec.set_len(len - del_bytes); - } + unsafe { + self.vec.set_len(len - del_bytes); } } diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index a6e41b21b61..b28694186b6 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; use std::ops::Bound::*; +use std::panic; pub trait IntoCow<'a, B: ?Sized> where @@ -378,6 +379,20 @@ fn test_retain() { s.retain(|_| false); assert_eq!(s, ""); + + let mut s = String::from("0รจ0"); + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let mut count = 0; + s.retain(|_| { + count += 1; + match count { + 1 => false, + 2 => true, + _ => panic!(), + } + }); + })); + assert!(std::str::from_utf8(s.as_bytes()).is_ok()); } #[test] |
