Skip to content

Commit c891dd6

Browse files
authored
Allow only u32 ref counts (#721)
1 parent 6af196c commit c891dd6

File tree

8 files changed

+48
-38
lines changed

8 files changed

+48
-38
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ ntex-macros = { path = "ntex-macros" }
4040
ntex-util = { path = "ntex-util" }
4141

4242
[workspace.dependencies]
43-
ntex = "3.0.0-pre.11"
44-
ntex-bytes = "1.4.0"
43+
ntex = "3.0.0-pre.13"
44+
ntex-bytes = "1.4.1"
4545
ntex-codec = "1.1.0"
4646
ntex-io = "3.5.0"
4747
ntex-net = "3.5.1"

ntex-bytes/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changes
22

3+
## [1.4.1] (2026-01-22)
4+
5+
* Allow only u32 ref counts
6+
37
## [1.4.0] (2026-01-21)
48

59
* Add BytesMut::reserve_capacity() method

ntex-bytes/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ntex-bytes"
3-
version = "1.4.0"
3+
version = "1.4.1"
44
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
55
description = "Types and traits for working with bytes (bytes crate fork)"
66
documentation = "https://docs.rs/ntex-bytes"

ntex-bytes/src/buf/buf_mut.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,11 +1026,11 @@ mod tests {
10261026
let mut buf = BytesMut::new();
10271027
buf.put_i8(0x01);
10281028
assert_eq!(buf, b"\x01"[..]);
1029-
assert_eq!((&mut buf).remaining_mut(), 103);
1029+
assert_eq!((&mut buf).remaining_mut(), 107);
10301030
let chunk = (&mut buf).chunk_mut();
10311031
chunk.write_byte(0, b'9');
10321032
unsafe { (&mut buf).advance_mut(1) };
1033-
assert_eq!((&mut buf).remaining_mut(), 102);
1033+
assert_eq!((&mut buf).remaining_mut(), 106);
10341034

10351035
let mut buf = vec![];
10361036
buf.put_i16(0x0809);

ntex-bytes/src/bvec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl BytesMut {
112112
#[inline]
113113
pub fn new() -> BytesMut {
114114
BytesMut {
115-
storage: StorageVec::with_capacity(104),
115+
storage: StorageVec::with_capacity(crate::storage::MIN_CAPACITY),
116116
}
117117
}
118118

ntex-bytes/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub mod info {
8080
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
8181
pub struct Info {
8282
pub id: usize,
83-
pub refs: usize,
83+
pub refs: u32,
8484
pub kind: Kind,
8585
pub capacity: usize,
8686
}

ntex-bytes/src/storage.rs

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
use crate::alloc::alloc::{self, Layout, LayoutError};
9797

9898
use std::sync::atomic::Ordering::{Acquire, Relaxed, Release};
99-
use std::sync::atomic::{self, AtomicUsize};
99+
use std::sync::atomic::{self, AtomicU32};
100100
use std::{cmp, mem, num::NonZeroUsize, ptr, ptr::NonNull, slice};
101101

102102
use crate::{info::Info, info::Kind};
@@ -117,12 +117,14 @@ pub(crate) struct Storage {
117117
offset: NonZeroUsize,
118118
}
119119

120+
#[derive(Debug)]
120121
/// Thread-safe reference-counted container for the shared storage.
121122
struct SharedVec {
122-
len: u32,
123123
offset: u32,
124+
len: u32,
125+
capacity: u32,
124126
remaining: u32,
125-
ref_count: AtomicUsize,
127+
ref_count: AtomicU32,
126128
}
127129

128130
pub(crate) struct StorageVec(NonNull<SharedVec>);
@@ -138,6 +140,8 @@ const KIND_OFFSET_BITS: usize = 2;
138140
pub const METADATA_SIZE: usize = mem::size_of::<SharedVec>();
139141
const METADATA_SIZE_U32: u32 = METADATA_SIZE as u32;
140142

143+
pub(crate) const MIN_CAPACITY: usize = 128 - crate::METADATA_SIZE;
144+
141145
// Bit op constants for extracting the inline length value from the `ptr` field.
142146
const INLINE_LEN_MASK: usize = 0b1111_1100;
143147

@@ -493,7 +497,7 @@ impl Storage {
493497
// ptr points to SharedVec
494498
let shared = self.shared_vec();
495499
let ref_cnt = (*shared).ref_count.fetch_add(1, Relaxed);
496-
if ref_cnt == usize::MAX {
500+
if ref_cnt == u32::MAX {
497501
abort();
498502
}
499503

@@ -649,8 +653,7 @@ impl StorageVec {
649653
}
650654

651655
pub(crate) fn capacity(&self) -> usize {
652-
let ptr = unsafe { &*self.0.as_ptr() };
653-
ptr.len as usize + ptr.remaining as usize
656+
unsafe { (*self.0.as_ptr()).capacity as usize }
654657
}
655658

656659
pub(crate) fn remaining(&self) -> usize {
@@ -686,7 +689,10 @@ impl StorageVec {
686689
Storage::from_ptr_inline(ptr, at)
687690
} else {
688691
let inner = self.as_inner();
689-
inner.ref_count.fetch_add(1, Relaxed);
692+
let ref_cnt = inner.ref_count.fetch_add(1, Relaxed);
693+
if ref_cnt == u32::MAX {
694+
abort();
695+
}
690696

691697
let offset = inner.offset as usize;
692698
Storage {
@@ -710,12 +716,11 @@ impl StorageVec {
710716
if len == 0 {
711717
let inner = self.as_inner();
712718
if inner.is_unique() && inner.offset != METADATA_SIZE_U32 {
713-
let cap = (inner.offset as usize)
714-
+ inner.len as usize
715-
+ inner.remaining as usize;
719+
let cap = (inner.offset as usize) + inner.capacity as usize;
716720
inner.len = 0;
717721
inner.offset = METADATA_SIZE_U32;
718-
inner.remaining = (cap - METADATA_SIZE) as u32;
722+
inner.capacity = (cap - METADATA_SIZE) as u32;
723+
inner.remaining = inner.capacity;
719724
return;
720725
}
721726
}
@@ -768,16 +773,15 @@ impl StorageVec {
768773
let new_cap = len + additional;
769774

770775
if inner.is_unique() {
771-
let capacity = (inner.offset as usize)
772-
+ (inner.len as usize)
773-
+ (inner.remaining as usize);
776+
let capacity = (inner.offset as usize) + (inner.capacity as usize);
774777

775778
// try to reclaim the buffer. This is possible if the current
776779
// handle is the only outstanding handle pointing to the buffer.
777780
if capacity >= (new_cap + METADATA_SIZE) {
778781
let offset = inner.offset;
779782
inner.offset = METADATA_SIZE_U32;
780783
inner.remaining = (capacity - len - METADATA_SIZE) as u32;
784+
inner.capacity = inner.len + inner.remaining;
781785

782786
// The capacity is sufficient, reclaim the buffer
783787
if len != 0 {
@@ -794,24 +798,23 @@ impl StorageVec {
794798

795799
#[inline]
796800
pub(crate) unsafe fn set_len(&mut self, len: usize) {
797-
let cap = self.capacity();
798-
assert!(len <= cap);
801+
let inner = self.0.as_mut();
802+
assert!(len as u32 <= inner.capacity);
799803

800-
let vec = self.0.as_mut();
801-
vec.len = len as u32;
802-
vec.remaining = (cap - len) as u32;
804+
inner.len = len as u32;
805+
inner.remaining = inner.capacity - (len as u32);
803806
}
804807

805808
pub(crate) unsafe fn set_start(&mut self, start: u32) {
806809
if start != 0 {
807-
let cap = self.capacity();
808810
let inner = self.as_inner();
809811

810812
assert!(
811-
start <= cap as u32,
812-
"Cannot set start position offset:{} len:{} remaining:{}, new-len:{start}",
813+
start <= inner.capacity,
814+
"Cannot set start position offset:{} len:{} cap:{} remaining:{} new-len:{start}",
813815
inner.offset,
814816
inner.len,
817+
inner.capacity,
815818
inner.remaining,
816819
);
817820

@@ -825,7 +828,8 @@ impl StorageVec {
825828
} else {
826829
inner.len = 0;
827830
}
828-
inner.remaining = cap as u32 - inner.len - start;
831+
inner.remaining = inner.capacity - inner.len - start;
832+
inner.capacity = inner.remaining + inner.len;
829833
}
830834
}
831835
}
@@ -861,14 +865,16 @@ impl SharedVec {
861865
if ptr.is_null() {
862866
alloc::handle_alloc_error(layout);
863867
}
868+
let capacity = (layout.size() - METADATA_SIZE) as u32;
864869

865870
ptr::write(
866871
ptr as *mut SharedVec,
867872
SharedVec {
868873
len,
874+
capacity,
875+
remaining: capacity - len,
869876
offset: METADATA_SIZE_U32,
870-
remaining: (layout.size() - METADATA_SIZE - len as usize) as u32,
871-
ref_count: AtomicUsize::new(1),
877+
ref_count: AtomicU32::new(1),
872878
},
873879
);
874880
ptr
@@ -881,7 +887,7 @@ impl SharedVec {
881887
}
882888

883889
fn capacity(&self) -> usize {
884-
self.len as usize + self.remaining as usize
890+
self.capacity as usize
885891
}
886892
}
887893

@@ -912,7 +918,7 @@ fn release_shared_vec(ptr: *mut SharedVec) {
912918
atomic::fence(Acquire);
913919

914920
// Drop the data
915-
let cap = (*ptr).offset as usize + (*ptr).remaining as usize + (*ptr).len as usize;
921+
let cap = (*ptr).offset as usize + (*ptr).capacity as usize;
916922
ptr::drop_in_place(ptr);
917923
let layout = shared_vec_layout(cap - METADATA_SIZE).unwrap();
918924
alloc::dealloc(ptr as *mut _, layout);

ntex-bytes/tests/test_bytes.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn is_send<T: Send>() {}
2020
fn test_size() {
2121
assert_eq!(24, std::mem::size_of::<Bytes>());
2222
assert_eq!(24, std::mem::size_of::<Option<Bytes>>());
23-
assert_eq!(24, ntex_bytes::METADATA_SIZE);
23+
assert_eq!(20, ntex_bytes::METADATA_SIZE);
2424

2525
let mut t = BytesMut::new();
2626
t.extend_from_slice(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"[..]);
@@ -409,15 +409,15 @@ fn fns_defined_for_bytes() {
409409
let bytes = Bytes::copy_from_slice(&B[..]);
410410
assert!(bytes.info().kind == Kind::Vec);
411411
assert!(bytes.info().refs == 1);
412-
assert_eq!(bytes.info().capacity, 76);
412+
assert_eq!(bytes.info().capacity, 72);
413413
let b2 = bytes.clone();
414414
assert!(b2.info().kind == Kind::Vec);
415415
assert!(b2.info().refs == 2);
416-
assert!(b2.info().capacity == 76);
416+
assert!(b2.info().capacity == 72);
417417
drop(b2);
418418
assert!(bytes.info().kind == Kind::Vec);
419419
assert!(bytes.info().refs == 1);
420-
assert!(bytes.info().capacity == 76);
420+
assert!(bytes.info().capacity == 72);
421421

422422
let mut bytes = Bytes::from(&b"hello world"[..]);
423423

0 commit comments

Comments
 (0)