From 724476982b35f094b59d160ecc02c042082ac604 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 6 Apr 2022 10:59:20 -0400 Subject: [PATCH] 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. --- src/bytes.rs | 23 ++++++++++++++++++----- 1 file 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, + // 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`.