summaryrefslogtreecommitdiff
path: root/vendor/bytes/tests/test_bytes_vec_alloc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/bytes/tests/test_bytes_vec_alloc.rs')
-rw-r--r--vendor/bytes/tests/test_bytes_vec_alloc.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/vendor/bytes/tests/test_bytes_vec_alloc.rs b/vendor/bytes/tests/test_bytes_vec_alloc.rs
new file mode 100644
index 00000000..9c760171
--- /dev/null
+++ b/vendor/bytes/tests/test_bytes_vec_alloc.rs
@@ -0,0 +1,146 @@
+#![cfg(not(miri))]
+use std::alloc::{GlobalAlloc, Layout, System};
+use std::ptr::null_mut;
+use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
+
+use bytes::{Buf, Bytes};
+
+#[global_allocator]
+static LEDGER: Ledger = Ledger::new();
+
+const LEDGER_LENGTH: usize = 1024 * 1024;
+
+struct Ledger {
+ alloc_table: [(AtomicPtr<u8>, AtomicUsize); LEDGER_LENGTH],
+}
+
+impl Ledger {
+ const fn new() -> Self {
+ const ELEM: (AtomicPtr<u8>, AtomicUsize) =
+ (AtomicPtr::new(null_mut()), AtomicUsize::new(0));
+ let alloc_table = [ELEM; LEDGER_LENGTH];
+
+ Self { alloc_table }
+ }
+
+ /// Iterate over our table until we find an open entry, then insert into said entry
+ fn insert(&self, ptr: *mut u8, size: usize) {
+ for (entry_ptr, entry_size) in self.alloc_table.iter() {
+ // SeqCst is good enough here, we don't care about perf, i just want to be correct!
+ if entry_ptr
+ .compare_exchange(null_mut(), ptr, Ordering::SeqCst, Ordering::SeqCst)
+ .is_ok()
+ {
+ entry_size.store(size, Ordering::SeqCst);
+ return;
+ }
+ }
+
+ panic!("Ledger ran out of space.");
+ }
+
+ fn remove(&self, ptr: *mut u8) -> usize {
+ for (entry_ptr, entry_size) in self.alloc_table.iter() {
+ // set the value to be something that will never try and be deallocated, so that we
+ // don't have any chance of a race condition
+ //
+ // dont worry, LEDGER_LENGTH is really long to compensate for us not reclaiming space
+ if entry_ptr
+ .compare_exchange(
+ ptr,
+ invalid_ptr(usize::MAX),
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ )
+ .is_ok()
+ {
+ return entry_size.load(Ordering::SeqCst);
+ }
+ }
+
+ panic!("Couldn't find a matching entry for {:x?}", ptr);
+ }
+}
+
+unsafe impl GlobalAlloc for Ledger {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ let size = layout.size();
+ let ptr = System.alloc(layout);
+ self.insert(ptr, size);
+ ptr
+ }
+
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ let orig_size = self.remove(ptr);
+
+ if orig_size != layout.size() {
+ panic!(
+ "bad dealloc: alloc size was {}, dealloc size is {}",
+ orig_size,
+ layout.size()
+ );
+ } else {
+ System.dealloc(ptr, layout);
+ }
+ }
+}
+
+#[test]
+fn test_bytes_advance() {
+ let mut bytes = Bytes::from(vec![10, 20, 30]);
+ bytes.advance(1);
+ drop(bytes);
+}
+
+#[test]
+fn test_bytes_truncate() {
+ let mut bytes = Bytes::from(vec![10, 20, 30]);
+ bytes.truncate(2);
+ drop(bytes);
+}
+
+#[test]
+fn test_bytes_truncate_and_advance() {
+ let mut bytes = Bytes::from(vec![10, 20, 30]);
+ bytes.truncate(2);
+ bytes.advance(1);
+ drop(bytes);
+}
+
+/// Returns a dangling pointer with the given address. This is used to store
+/// integer data in pointer fields.
+#[inline]
+fn invalid_ptr<T>(addr: usize) -> *mut T {
+ let ptr = std::ptr::null_mut::<u8>().wrapping_add(addr);
+ debug_assert_eq!(ptr as usize, addr);
+ ptr.cast::<T>()
+}
+
+#[test]
+fn test_bytes_into_vec() {
+ let vec = vec![33u8; 1024];
+
+ // Test cases where kind == KIND_VEC
+ let b1 = Bytes::from(vec.clone());
+ assert_eq!(Vec::from(b1), vec);
+
+ // Test cases where kind == KIND_ARC, ref_cnt == 1
+ let b1 = Bytes::from(vec.clone());
+ drop(b1.clone());
+ assert_eq!(Vec::from(b1), vec);
+
+ // Test cases where kind == KIND_ARC, ref_cnt == 2
+ let b1 = Bytes::from(vec.clone());
+ let b2 = b1.clone();
+ assert_eq!(Vec::from(b1), vec);
+
+ // Test cases where vtable = SHARED_VTABLE, kind == KIND_ARC, ref_cnt == 1
+ assert_eq!(Vec::from(b2), vec);
+
+ // Test cases where offset != 0
+ let mut b1 = Bytes::from(vec.clone());
+ let b2 = b1.split_off(20);
+
+ assert_eq!(Vec::from(b2), vec[20..]);
+ assert_eq!(Vec::from(b1), vec[..20]);
+}