about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrik Sverdrup <bluss@users.noreply.github.com>2016-03-05 18:09:14 +0100
committerUlrik Sverdrup <bluss@users.noreply.github.com>2016-03-05 18:11:52 +0100
commit4594f0f67aad77839d5a41353224fee186bfcda9 (patch)
tree0eb1684d1a6de19110ef4e92a9acdfee2883b629
parentc97524bef9e59a80875110b402b3fc8c139d4d64 (diff)
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.rs20
-rw-r--r--src/libcore/str/mod.rs24
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")]