From 33bc557dd48c4693329a0403d5b3f224999b029d Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 2 Jul 2024 19:50:39 -0500 Subject: [PATCH 1/3] Add test case demonstrating equality of paths "foo/bar" and "foobar" --- std/src/path/tests.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/std/src/path/tests.rs b/std/src/path/tests.rs index 92702b395dfe1..53a65c60b580c 100644 --- a/std/src/path/tests.rs +++ b/std/src/path/tests.rs @@ -1566,6 +1566,13 @@ pub fn test_compare() { relative_from: Some("bar") ); + tc!("foo/bar", "foobar", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); + tc!("foo/bar/baz", "foo/bar", eq: false, starts_with: true, From 5ca124f6d8a71e886937ad8b3ceea304707ab65c Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 2 Jul 2024 23:12:06 -0500 Subject: [PATCH 2/3] Add more test cases for path comparisons --- std/src/path/tests.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/std/src/path/tests.rs b/std/src/path/tests.rs index 53a65c60b580c..87a06a9ea9153 100644 --- a/std/src/path/tests.rs +++ b/std/src/path/tests.rs @@ -1545,6 +1545,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo//", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo///", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/.", "foo", eq: true, starts_with: true, @@ -1559,6 +1573,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo/.//bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo//./bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/bar", "foo", eq: false, starts_with: true, From ed3d4878d341779cab86249b4365806643de24cf Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 3 Jul 2024 22:54:15 +0200 Subject: [PATCH 3/3] stir the hash state a little to avoid prefix collisions --- std/src/path.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/std/src/path.rs b/std/src/path.rs index caae8f924d2b1..e8f0b41f1f4c3 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -3098,15 +3098,19 @@ impl Hash for Path { let bytes = &bytes[prefix_len..]; let mut component_start = 0; - let mut bytes_hashed = 0; + // track some extra state to avoid prefix collisions. + // ["foo", "bar"] and ["foobar"], will have the same payload bytes + // but result in different chunk_bits + let mut chunk_bits: usize = 0; for i in 0..bytes.len() { let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) }; if is_sep { if i > component_start { let to_hash = &bytes[component_start..i]; + chunk_bits = chunk_bits.wrapping_add(to_hash.len()); + chunk_bits = chunk_bits.rotate_right(2); h.write(to_hash); - bytes_hashed += to_hash.len(); } // skip over separator and optionally a following CurDir item @@ -3127,11 +3131,12 @@ impl Hash for Path { if component_start < bytes.len() { let to_hash = &bytes[component_start..]; + chunk_bits = chunk_bits.wrapping_add(to_hash.len()); + chunk_bits = chunk_bits.rotate_right(2); h.write(to_hash); - bytes_hashed += to_hash.len(); } - h.write_usize(bytes_hashed); + h.write_usize(chunk_bits); } }