difftreelog
fix(interner) data should be in UnsafeCell
in: master
2 files changed
crates/jrsonnet-interner/src/inner.rsdiffbeforeafterboth1use std::{1use std::{2 alloc::{self, Layout},2 alloc::{self, Layout},3 borrow::Borrow,3 borrow::Borrow,4 cell::UnsafeCell,4 cmp,5 cmp,5 hash::{Hash, Hasher},6 hash::{Hash, Hasher},6 mem,7 mem,45}46}464747/// Similar to Rc<[u8]>, but stores all data (refcnt, size) inline, instead of being DST48/// Similar to Rc<[u8]>, but stores all data (refcnt, size) inline, instead of being DST48pub struct Inner(NonNull<u8>);49pub struct Inner(UnsafeCell<NonNull<InnerHeader>>);49impl Inner {50impl Inner {50 /// # Safety51 /// # Safety51 /// `is_utf8` should only be set if data is really checked to be utf852 /// `is_utf8` should only be set if data is really checked to be utf859 // - data is written right after allocation60 // - data is written right after allocation60 // - new allocation can't overlap with passed slice61 // - new allocation can't overlap with passed slice61 unsafe {62 unsafe {62 let data = alloc::alloc(Layout::from_size_align_unchecked(63 let data: *mut InnerHeader = alloc::alloc(Layout::from_size_align_unchecked(63 mem::size_of::<InnerHeader>() + bytes.len(),64 mem::size_of::<InnerHeader>() + bytes.len(),64 mem::align_of::<InnerHeader>(),65 mem::align_of::<InnerHeader>(),65 ));66 ))67 .cast();66 assert!(!data.is_null());68 assert!(!data.is_null());67 *data.cast::<InnerHeader>() =69 *data = InnerHeader::new(bytes.len().try_into().expect("bytes > 4GB"), is_utf8);68 InnerHeader::new(bytes.len().try_into().expect("bytes > 4GB"), is_utf8);69 ptr::copy_nonoverlapping(70 ptr::copy_nonoverlapping(bytes.as_ptr(), data.offset(1).cast::<u8>(), bytes.len());70 bytes.as_ptr(),71 data.add(mem::size_of::<InnerHeader>()),72 bytes.len(),73 );74 Self(NonNull::new_unchecked(data))71 Self(UnsafeCell::new(NonNull::new_unchecked(data)))75 }72 }76 }73 }77 pub fn new_bytes(bytes: &[u8]) -> Self {74 pub fn new_bytes(bytes: &[u8]) -> Self {93 // SAFETY: bytes after data is allocated to be exactly data.size in length90 // SAFETY: bytes after data is allocated to be exactly data.size in length94 unsafe {91 unsafe {95 slice::from_raw_parts(92 slice::from_raw_parts(96 self.0.as_ptr().add(mem::size_of::<InnerHeader>()),93 (*self.0.get()).as_ptr().offset(1).cast::<u8>(),97 size as usize,94 size as usize,98 )95 )99 }96 }135 unsafe { (*header).set_is_utf8() }132 unsafe { (*header).set_is_utf8() }136 }133 }137134138 const fn header(this: &Self) -> *const InnerHeader {135 fn header(this: &Self) -> *const InnerHeader {139 // in `new`, we allocate with correct alignment136 // Safety: in `new`, we allocate with correct alignment140 #![allow(clippy::cast_ptr_alignment)]141 this.0.as_ptr() as *const InnerHeader137 unsafe { (*this.0.get()).as_ptr() }142 }138 }143 const fn header_mut(this: &Self) -> *mut InnerHeader {139 fn header_mut(this: &Self) -> *mut InnerHeader {144 // in `new`, we allocate with correct alignment140 // Safety: in `new`, we allocate with correct alignment145 #![allow(clippy::cast_ptr_alignment)]146 this.0.as_ptr().cast::<InnerHeader>()141 unsafe { (*this.0.get()).as_mut() }147 }142 }148143149 fn clone(this: &Self) -> Self {144 fn clone(this: &Self) -> Self {150 let header = Self::header_mut(this);145 let header = Self::header_mut(this);151 // SAFETY: header is initialized146 // SAFETY: header is initialized152 unsafe {147 unsafe {153 let refcnt = (*header).refcnt() + 1;148 let refcnt = (*header).refcnt() + 1;154 (*header).set_refcnt(refcnt);149 (*header).set_refcnt(refcnt);155 }156 Self(this.0)150 Self(UnsafeCell::new(*this.0.get()))151 }157 }152 }158153159 pub fn ptr_eq(a: &Self, b: &Self) -> bool {154 pub fn ptr_eq(a: &Self, b: &Self) -> bool {160 a.0 == b.0155 Self::as_ptr(a) == Self::as_ptr(b)161 }156 }162 pub const fn as_ptr(this: &Self) -> *const u8 {157 pub fn as_ptr(this: &Self) -> *const u8 {163 // SAFETY: data is initialized158 // SAFETY: data is initialized164 unsafe { this.0.as_ptr().add(mem::size_of::<InnerHeader>()) }159 unsafe { (*this.0.get()).as_ptr().offset(1).cast() }165 }160 }166161167 pub const fn strong_count(this: &Self) -> u32 {162 pub fn strong_count(this: &Self) -> u32 {168 let header = Self::header(this);163 let header = Self::header(this);169 // SAFETY: header is initialized164 // SAFETY: header is initialized170 unsafe { (*header).refcnt() }165 unsafe { (*header).refcnt() }183 #[inline(never)]178 #[inline(never)]184 fn dealloc(val: &Inner) {179 fn dealloc(val: &Inner) {185 let header = Inner::header_mut(val);180 let header = Inner::header_mut(val);186 // SAFETY: size is correct, layout is valid181 // Safety: Data is valid yet182 let size = unsafe { (*header).size as usize };183 // SAFETY: size is correct, layout is valid, data will not be used after this, as refcn == 0187 unsafe {184 unsafe {188 alloc::dealloc(185 alloc::dealloc(189 val.0.as_ptr(),186 header.cast(),190 Layout::from_size_align_unchecked(187 Layout::from_size_align_unchecked(191 mem::size_of::<InnerHeader>() + (*header).size as usize,188 mem::size_of::<InnerHeader>() + size,192 mem::align_of::<InnerHeader>(),189 mem::align_of::<InnerHeader>(),193 ),190 ),194 );191 );209206210impl PartialEq for Inner {207impl PartialEq for Inner {211 fn eq(&self, other: &Self) -> bool {208 fn eq(&self, other: &Self) -> bool {212 self.0 == other.0 || self.as_slice().eq(other.as_slice())209 Self::as_ptr(self) == Self::as_ptr(other) || self.as_slice().eq(other.as_slice())213 }210 }214}211}215impl Hash for Inner {212impl Hash for Inner {crates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth174 }174 }175 // First reference - current object, second - POOL175 // First reference - current object, second - POOL176 if Inner::strong_count(&self.0) <= 2 {176 if Inner::strong_count(&self.0) <= 2 {177 eprintln!("unpool");177 unpool(&self.0);178 unpool(&self.0);178 }179 }179 }180 }275 unsafe { intern_bytes(str.as_bytes()).cast_str_unchecked() }276 unsafe { intern_bytes(str.as_bytes()).cast_str_unchecked() }276}277}278279#[cfg(test)]280mod tests {281 use crate::IStr;282283 #[test]284 fn simple() {285 let a = IStr::from("a");286 let b = IStr::from("a");287288 assert_eq!(a.as_ptr(), b.as_ptr());289 }290}277291