diff --git a/src/bytes.rs b/src/bytes.rs index aed4d7cdb..7e2d6d115 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -700,6 +700,15 @@ impl Buf for Bytes { self.len(), ); + if cnt == self.len() { + // Advancing to the end leaves an empty `Bytes`, whose length can + // never grow again. Release the shared reference instead of + // retaining it, matching `truncate(0)` and `split_to(self.len())`. + let end_ptr = self.ptr.wrapping_add(cnt); + drop(mem::replace(self, Bytes::new_empty_with_ptr(end_ptr))); + return; + } + unsafe { self.inc_start(cnt); } diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 5d01b5b82..7ce66b4eb 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -364,6 +364,31 @@ fn truncate_to_zero_releases_shared_reference() { assert!(remaining.try_into_mut().is_err()); } +#[test] +fn advance_to_end_releases_shared_reference() { + let mut bytes = BytesMut::from(&b"hello"[..]); + drop(bytes.split_off(bytes.len())); + let mut advanced = bytes.freeze(); + let remaining = advanced.clone(); + + advanced.advance(5); + + assert!(advanced.is_empty()); + let mut remaining = remaining.try_into_mut().unwrap(); + remaining[0] = b'H'; + assert_eq!(remaining, b"Hello"[..]); + + let mut bytes = BytesMut::from(&b"hello"[..]); + drop(bytes.split_off(bytes.len())); + let mut nonempty = bytes.freeze(); + let remaining = nonempty.clone(); + + nonempty.advance(4); + + assert_eq!(nonempty, b"o"[..]); + assert!(remaining.try_into_mut().is_err()); +} + #[test] fn freeze_clone_shared() { let s = &b"abcdefgh"[..];