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)
downloadrust-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.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")]