Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Appease miri #515

Merged
merged 12 commits into from
Nov 7, 2021
Merged
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Expand Up @@ -11,7 +11,7 @@ on:
env:
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
nightly: nightly-2021-04-13
nightly: nightly-2021-11-05

defaults:
run:
Expand Down
94 changes: 55 additions & 39 deletions tests/test_bytes_vec_alloc.rs
@@ -1,61 +1,77 @@
use std::alloc::{GlobalAlloc, Layout, System};
use std::{mem, ptr};
use std::ptr::null_mut;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};

use bytes::{Buf, Bytes};

#[global_allocator]
static LEDGER: Ledger = Ledger;
static LEDGER: Ledger = Ledger::new();

struct Ledger;
#[repr(C)]
struct Ledger {
alloc_table: [(AtomicPtr<u8>, AtomicUsize); 512],
}

const USIZE_SIZE: usize = mem::size_of::<usize>();
impl Ledger {
const fn new() -> Self {
const ELEM: (AtomicPtr<u8>, AtomicUsize) =
(AtomicPtr::new(null_mut()), AtomicUsize::new(0));
let alloc_table = [ELEM; 512];

unsafe impl GlobalAlloc for Ledger {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.align() == 1 && layout.size() > 0 {
// Allocate extra space to stash a record of
// how much space there was.
let orig_size = layout.size();
let size = orig_size + USIZE_SIZE;
let new_layout = match Layout::from_size_align(size, 1) {
Ok(layout) => layout,
Err(_err) => return ptr::null_mut(),
};
let ptr = System.alloc(new_layout);
if !ptr.is_null() {
(ptr as *mut usize).write(orig_size);
let ptr = ptr.offset(USIZE_SIZE as isize);
ptr
} else {
ptr
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);
break;
}
} else {
System.alloc(layout)
}
}

unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if layout.align() == 1 && layout.size() > 0 {
let off_ptr = (ptr as *mut usize).offset(-1);
let orig_size = off_ptr.read();
if orig_size != layout.size() {
panic!(
"bad dealloc: alloc size was {}, dealloc size is {}",
orig_size,
layout.size()
);
fn remove(&self, ptr: *mut u8) -> usize {
for (entry_ptr, entry_size) in self.alloc_table.iter() {
if entry_ptr
.compare_exchange(ptr, null_mut(), Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
return entry_size.swap(0, Ordering::SeqCst);
}
}

panic!("Couldn't find a matching entry for {:x?}", ptr);
}
}

let new_layout = match Layout::from_size_align(layout.size() + USIZE_SIZE, 1) {
Ok(layout) => layout,
Err(_err) => std::process::abort(),
};
System.dealloc(off_ptr as *mut u8, new_layout);
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]);
Expand Down