diff options
author | 2022-04-06 10:59:20 -0400 | |
---|---|---|
committer | 2022-04-06 16:59:20 +0200 | |
commit | 724476982b35f094b59d160ecc02c042082ac604 (patch) | |
tree | e001e4f702e7418f15d83df60a3d13bc606e5a89 /src | |
parent | 9e6edd18d297ec1b1bf9e01b1fce7a52eacdd8cc (diff) | |
download | bytes-724476982b35f094b59d160ecc02c042082ac604.tar.gz bytes-724476982b35f094b59d160ecc02c042082ac604.tar.zst bytes-724476982b35f094b59d160ecc02c042082ac604.zip |
Fix aliasing in Clone by using a raw pointer (#523)
Previously, this code produced a &mut[u8] and a Box<[u8]> to the shared
allocation upon cloning it. If the underlying allocation were actually
shared, such as through a &[u8] from the Deref impl, creating either of
these types incorrectly asserted uniqueness of the allocation.
This fixes the example in #522, but Miri still does not pass on this
test suite with -Zmiri-tag-raw-pointers because Miri does not currently
understand int to pointer casts.
Diffstat (limited to 'src')
-rw-r--r-- | src/bytes.rs | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/src/bytes.rs b/src/bytes.rs index 753bb5c..24c2137 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -2,7 +2,13 @@ use core::iter::FromIterator; use core::ops::{Deref, RangeBounds}; use core::{cmp, fmt, hash, mem, ptr, slice, usize}; -use alloc::{borrow::Borrow, boxed::Box, string::String, vec::Vec}; +use alloc::{ + alloc::{dealloc, Layout}, + borrow::Borrow, + boxed::Box, + string::String, + vec::Vec, +}; use crate::buf::IntoIter; #[allow(unused)] @@ -941,11 +947,18 @@ unsafe fn rebuild_boxed_slice(buf: *mut u8, offset: *const u8, len: usize) -> Bo // ===== impl SharedVtable ===== struct Shared { - // holds vec for drop, but otherwise doesnt access it - _vec: Vec<u8>, + // Holds arguments to dealloc upon Drop, but otherwise doesn't use them + buf: *mut u8, + cap: usize, ref_cnt: AtomicUsize, } +impl Drop for Shared { + fn drop(&mut self) { + unsafe { dealloc(self.buf, Layout::from_size_align(self.cap, 1).unwrap()) } + } +} + // Assert that the alignment of `Shared` is divisible by 2. // This is a necessary invariant since we depend on allocating `Shared` a // shared object to implicitly carry the `KIND_ARC` flag in its pointer. @@ -1006,9 +1019,9 @@ unsafe fn shallow_clone_vec( // updated and since the buffer hasn't been promoted to an // `Arc`, those three fields still are the components of the // vector. - let vec = rebuild_boxed_slice(buf, offset, len).into_vec(); let shared = Box::new(Shared { - _vec: vec, + buf, + cap: (offset as usize - buf as usize) + len, // Initialize refcount to 2. One for this reference, and one // for the new clone that will be returned from // `shallow_clone`. |