Fix panic on string slicing error to truncate the string

The string may be arbitrarily long, but we want to limit the panic
message to a reasonable length. Truncate the string if it is too long
(simply to char boundary).

Also add details to the start <= end message. I think it's ok to flesh
out the code here, since it's in a cold function.
This commit is contained in:
Ulrik Sverdrup 2016-03-05 18:09:14 +01:00
parent c97524bef9
commit 4594f0f67a
2 changed files with 41 additions and 3 deletions

View File

@ -346,6 +346,26 @@ fn test_slice_fail() {
&"中华Việt Nam"[0..2];
}
const LOREM_PARAGRAPH: &'static str = "\
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
tempus vel, gravida nec quam.";
// check the panic includes the prefix of the sliced string
#[test]
#[should_panic(expected="Lorem ipsum dolor sit amet")]
fn test_slice_fail_truncated_1() {
&LOREM_PARAGRAPH[..1024];
}
// check the truncation in the panic message
#[test]
#[should_panic(expected="luctus, im`[...] do not lie on character boundary")]
fn test_slice_fail_truncated_2() {
&LOREM_PARAGRAPH[..1024];
}
#[test]
fn test_slice_from() {
assert_eq!(&"abcd"[0..], "abcd");

View File

@ -1591,12 +1591,30 @@ pub trait StrExt {
fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
}
// truncate `&str` to length at most equal to `max`
// return `true` if it were truncated, and the new str.
fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
if max >= s.len() {
(false, s)
} else {
while !s.is_char_boundary(max) {
max -= 1;
}
(true, &s[..max])
}
}
#[inline(never)]
#[cold]
fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
assert!(begin <= end);
panic!("index {} and/or {} in `{}` do not lie on character boundary",
begin, end, s);
const MAX_DISPLAY_LENGTH: usize = 256;
let (truncated, s) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
let ellipsis = if truncated { "[...]" } else { "" };
assert!(begin <= end, "begin <= end ({} <= {}) when slicing `{}`{}",
begin, end, s, ellipsis);
panic!("index {} and/or {} in `{}`{} do not lie on character boundary",
begin, end, s, ellipsis);
}
#[stable(feature = "core", since = "1.6.0")]