Skip to content

Commit f4bd5be

Browse files
Auto merge of #149447 - theemathas:string-replace_range, r=<try>
Rewrite `String::replace_range` try-job: i686-gnu-*
2 parents ba2142a + 6ee39cc commit f4bd5be

File tree

2 files changed

+26
-32
lines changed

2 files changed

+26
-32
lines changed

‎library/alloc/src/string.rs‎

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ use core::iter::from_fn;
5050
use core::ops::Add;
5151
#[cfg(not(no_global_oom_handling))]
5252
use core::ops::AddAssign;
53-
#[cfg(not(no_global_oom_handling))]
54-
use core::ops::Bound::{Excluded, Included, Unbounded};
5553
use core::ops::{self, Range, RangeBounds};
5654
use core::str::pattern::{Pattern, Utf8Pattern};
5755
use core::{fmt, hash, ptr, slice};
@@ -2062,30 +2060,19 @@ impl String {
20622060
where
20632061
R: RangeBounds<usize>,
20642062
{
2065-
// Memory safety
2066-
//
2067-
// Replace_range does not have the memory safety issues of a vector Splice.
2068-
// of the vector version. The data is just plain bytes.
2069-
2070-
// WARNING: Inlining this variable would be unsound (#81138)
2071-
let start = range.start_bound();
2072-
match start {
2073-
Included(&n) => assert!(self.is_char_boundary(n)),
2074-
Excluded(&n) => assert!(self.is_char_boundary(n + 1)),
2075-
Unbounded => {}
2076-
};
2077-
// WARNING: Inlining this variable would be unsound (#81138)
2078-
let end = range.end_bound();
2079-
match end {
2080-
Included(&n) => assert!(self.is_char_boundary(n + 1)),
2081-
Excluded(&n) => assert!(self.is_char_boundary(n)),
2082-
Unbounded => {}
2083-
};
2084-
2085-
// Using `range` again would be unsound (#81138)
2086-
// We assume the bounds reported by `range` remain the same, but
2087-
// an adversarial implementation could change between calls
2088-
unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes());
2063+
// We avoid #81138 (nondeterministic RangeBounds impls) because we only use `range` once, here.
2064+
let checked_range = slice::range(range, ..self.len());
2065+
2066+
assert!(
2067+
self.is_char_boundary(checked_range.start),
2068+
"start of range should be a character boundary"
2069+
);
2070+
assert!(
2071+
self.is_char_boundary(checked_range.end),
2072+
"end of range should be a character boundary"
2073+
);
2074+
2075+
unsafe { self.as_mut_vec() }.splice(checked_range, replace_with.bytes());
20892076
}
20902077

20912078
/// Replaces the leftmost occurrence of a pattern with another string, in-place.

‎library/alloctests/tests/string.rs‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,15 @@ fn test_replace_range() {
616616
}
617617

618618
#[test]
619-
#[should_panic]
620-
fn test_replace_range_char_boundary() {
619+
#[should_panic = "start of range should be a character boundary"]
620+
fn test_replace_range_start_char_boundary() {
621+
let mut s = "Hello, 世界!".to_owned();
622+
s.replace_range(8.., "");
623+
}
624+
625+
#[test]
626+
#[should_panic = "end of range should be a character boundary"]
627+
fn test_replace_range_end_char_boundary() {
621628
let mut s = "Hello, 世界!".to_owned();
622629
s.replace_range(..8, "");
623630
}
@@ -632,28 +639,28 @@ fn test_replace_range_inclusive_range() {
632639
}
633640

634641
#[test]
635-
#[should_panic]
642+
#[should_panic = "range end index 6 out of range for slice of length 5"]
636643
fn test_replace_range_out_of_bounds() {
637644
let mut s = String::from("12345");
638645
s.replace_range(5..6, "789");
639646
}
640647

641648
#[test]
642-
#[should_panic]
649+
#[should_panic = "range end index 5 out of range for slice of length 5"]
643650
fn test_replace_range_inclusive_out_of_bounds() {
644651
let mut s = String::from("12345");
645652
s.replace_range(5..=5, "789");
646653
}
647654

648655
#[test]
649-
#[should_panic]
656+
#[should_panic = "range start index 18446744073709551615 out of range for slice of length 3"]
650657
fn test_replace_range_start_overflow() {
651658
let mut s = String::from("123");
652659
s.replace_range((Excluded(usize::MAX), Included(0)), "");
653660
}
654661

655662
#[test]
656-
#[should_panic]
663+
#[should_panic = "range end index 18446744073709551615 out of range for slice of length 3"]
657664
fn test_replace_range_end_overflow() {
658665
let mut s = String::from("456");
659666
s.replace_range((Included(0), Included(usize::MAX)), "");

0 commit comments

Comments
 (0)