diff options
| author | Ulrik Sverdrup <bluss@users.noreply.github.com> | 2016-03-05 18:09:14 +0100 |
|---|---|---|
| committer | Ulrik Sverdrup <bluss@users.noreply.github.com> | 2016-03-05 18:11:52 +0100 |
| commit | 4594f0f67aad77839d5a41353224fee186bfcda9 (patch) | |
| tree | 0eb1684d1a6de19110ef4e92a9acdfee2883b629 | |
| parent | c97524bef9e59a80875110b402b3fc8c139d4d64 (diff) | |
| download | rust-4594f0f67aad77839d5a41353224fee186bfcda9.tar.gz rust-4594f0f67aad77839d5a41353224fee186bfcda9.zip | |
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.
| -rw-r--r-- | src/libcollectionstest/str.rs | 20 | ||||
| -rw-r--r-- | src/libcore/str/mod.rs | 24 |
2 files changed, 41 insertions, 3 deletions
diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index b84b37dbf75..462700318d7 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -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"); diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index a555b859291..b6f3e8e7583 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -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")] |
