Fix panic `trim_first_and_last_line_of_whitespace` on bad slice indices (#865)

* Fix panic from slice end being before slice start

* Fix fallback value for end index

Co-authored-by: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com>
This commit is contained in:
LovecraftianHorror 2021-12-20 02:07:01 -06:00 committed by GitHub
parent 46d447f0fd
commit 0152709e9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 2 deletions

78
Cargo.lock generated
View File

@ -55,6 +55,21 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bit-set"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
version = "1.2.1"
@ -775,6 +790,38 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "proptest"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"
dependencies = [
"bit-set",
"bitflags",
"byteorder",
"lazy_static",
"num-traits",
"quick-error 2.0.1",
"rand",
"rand_chacha",
"rand_xorshift",
"regex-syntax",
"rusty-fork",
"tempfile",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quick-error"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quote"
version = "1.0.9"
@ -824,6 +871,15 @@ dependencies = [
"rand_core",
]
[[package]]
name = "rand_xorshift"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
dependencies = [
"rand_core",
]
[[package]]
name = "rayon"
version = "1.5.1"
@ -894,6 +950,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "rusty-fork"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
dependencies = [
"fnv",
"quick-error 1.2.3",
"tempfile",
"wait-timeout",
]
[[package]]
name = "rustversion"
version = "1.0.6"
@ -1157,6 +1225,7 @@ dependencies = [
"num-format",
"once_cell",
"parking_lot",
"proptest",
"rayon",
"regex",
"serde",
@ -1302,6 +1371,15 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]]
name = "walkdir"
version = "2.3.2"

View File

@ -75,6 +75,7 @@ optional = true
version = "0.8.15"
[dev-dependencies]
proptest = "1.0.0"
strum = "0.23.0"
strum_macros = "0.23.0"
regex = "1.4.6"

View File

@ -38,9 +38,10 @@ impl SliceExt for [u8] {
.iter()
.rposition(|c| c.is_line_ending_whitespace() || !c.is_whitespace())
.map_or_else(
|| self.len(),
|| self.len().saturating_sub(1),
|i| {
if self[i.saturating_sub(1)] == b'\r' {
// Remove the entire `\r\n` in the case that it was the line ending whitespace
if self[i.saturating_sub(1)] == b'\r' && self[i] == b'\n' {
i - 1
} else {
i
@ -114,6 +115,8 @@ impl SliceExt for [u8] {
mod tests {
use super::*;
use proptest::prelude::*;
#[test]
fn is_whitespace() {
assert!(b' '.is_whitespace());
@ -142,4 +145,19 @@ mod tests {
assert!([1, 2, 3, 4, 5].contains_slice(&[2, 3, 4]));
assert!(![1, 2, 3, 4, 5].contains_slice(&[]));
}
#[test]
fn trim_first_and_last_line_of_whitespace_edge_cases() {
assert_eq!(b"", b"\ra ".trim_first_and_last_line_of_whitespace());
assert_eq!(b"a", b"\r\na ".trim_first_and_last_line_of_whitespace());
assert_eq!(b" ", b" ".trim_first_and_last_line_of_whitespace());
}
proptest! {
#[test]
fn trim_first_and_last_line_of_whitespace_doesnt_panic(input: Vec<u8>) {
let _ = &input.trim_first_and_last_line_of_whitespace();
}
}
}