Compare commits

...
2 Commits
Author SHA1 Message Date
d5c8ad3227 Release shared reference on zero truncate (#842)
Co-authored-by: JSap0914 <[email protected]>
2026-07-16 12:19:37 +02:00
bestgopherandGitHub 002df10b8c Simplify shared alignment assertions (#841)
Replace array-underflow checks with const assert expressions.
Add diagnostics that explain the pointer-tagging alignment invariant.

Signed-off-by: bestgopher <[email protected]>
2026-07-14 09:45:41 +02:00
3 changed files with 40 additions and 3 deletions
+9 -2
View File
@@ -567,7 +567,9 @@ impl Bytes {
/// ```
#[inline]
pub fn truncate(&mut self, len: usize) {
if len < self.len {
if len == 0 {
drop(mem::replace(self, Bytes::new_empty_with_ptr(self.ptr)));
} else if len < self.len {
// The Vec "promotable" vtables do not store the capacity,
// so we cannot truncate while using this repr. We *have* to
// promote using `split_off` so the capacity can be stored.
@@ -1348,7 +1350,12 @@ impl Drop for Shared {
// This is a necessary invariant since we depend on allocating `Shared` a
// shared object to implicitly carry the `KIND_ARC` flag in its pointer.
// This flag is set when the LSB is 0.
const _: [(); 0 - mem::align_of::<Shared>() % 2] = []; // Assert that the alignment of `Shared` is divisible by 2.
const _: () = {
assert!(
mem::align_of::<Shared>() % 2 == 0,
"Shared alignment must be divisible by 2 for pointer tagging"
);
};
static SHARED_VTABLE: Vtable = Vtable {
clone: shared_clone,
+6 -1
View File
@@ -92,7 +92,12 @@ impl Shared {
// This is a necessary invariant since we depend on allocating `Shared` a
// shared object to implicitly carry the `KIND_ARC` flag in its pointer.
// This flag is set when the LSB is 0.
const _: [(); 0 - mem::align_of::<Shared>() % 2] = []; // Assert that the alignment of `Shared` is divisible by 2.
const _: () = {
assert!(
mem::align_of::<Shared>() % 2 == 0,
"Shared alignment must be divisible by 2 for pointer tagging"
);
};
// Buffer storage strategy flags.
const KIND_ARC: usize = 0b0;
+25
View File
@@ -339,6 +339,31 @@ fn truncate() {
assert_eq!(hello, "hello");
}
#[test]
fn truncate_to_zero_releases_shared_reference() {
let mut bytes = BytesMut::from(&b"hello"[..]);
drop(bytes.split_off(bytes.len()));
let mut truncated = bytes.freeze();
let remaining = truncated.clone();
truncated.truncate(0);
assert!(truncated.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.truncate(1);
assert_eq!(nonempty, b"h"[..]);
assert!(remaining.try_into_mut().is_err());
}
#[test]
fn freeze_clone_shared() {
let s = &b"abcdefgh"[..];