Remove unsound cast in thread local resources (#749)

* Remove unsound cast in thread local resources

* Make ResourceRef(Mut)::new impossible to cause unsoundness with
This commit is contained in:
Boxy 2020-10-30 18:43:39 +00:00 committed by GitHub
parent 1d4a95db62
commit dea05e9af5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -33,7 +33,7 @@ trait ResourceStorage: Downcast {}
impl_downcast!(ResourceStorage); impl_downcast!(ResourceStorage);
struct StoredResource<T: 'static> { struct StoredResource<T: 'static> {
value: T, value: std::cell::UnsafeCell<T>,
atomic_borrow: AtomicBorrow, atomic_borrow: AtomicBorrow,
} }
@ -45,27 +45,24 @@ impl<T: 'static> VecResourceStorage<T> {
fn get(&self, index: usize) -> Option<ResourceRef<'_, T>> { fn get(&self, index: usize) -> Option<ResourceRef<'_, T>> {
self.stored self.stored
.get(index) .get(index)
.map(|stored| ResourceRef::new(&stored.value, &stored.atomic_borrow)) .map(|stored| ResourceRef::new(stored))
} }
fn get_mut(&self, index: usize) -> Option<ResourceRefMut<'_, T>> { fn get_mut(&self, index: usize) -> Option<ResourceRefMut<'_, T>> {
self.stored.get(index).map(|stored| self.stored
// SAFE: ResourceRefMut ensures that this borrow is unique .get(index)
unsafe { .map(|stored| ResourceRefMut::new(stored))
let value = &stored.value as *const T as *mut T;
ResourceRefMut::new(&mut *value, &stored.atomic_borrow)
})
} }
fn push(&mut self, resource: T) { fn push(&mut self, resource: T) {
self.stored.push(StoredResource { self.stored.push(StoredResource {
atomic_borrow: AtomicBorrow::new(), atomic_borrow: AtomicBorrow::new(),
value: resource, value: std::cell::UnsafeCell::new(resource),
}) })
} }
fn set(&mut self, index: usize, resource: T) { fn set(&mut self, index: usize, resource: T) {
self.stored[index].value = resource; self.stored[index].value = std::cell::UnsafeCell::new(resource);
} }
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {
@ -414,9 +411,24 @@ pub struct ResourceRef<'a, T: 'static> {
impl<'a, T: 'static> ResourceRef<'a, T> { impl<'a, T: 'static> ResourceRef<'a, T> {
/// Creates a new resource borrow /// Creates a new resource borrow
pub fn new(resource: &'a T, borrow: &'a AtomicBorrow) -> Self { fn new(
borrow.borrow(); StoredResource {
Self { resource, borrow } value,
atomic_borrow,
}: &'a StoredResource<T>,
) -> Self {
if atomic_borrow.borrow() {
Self {
// Safe because we acquired the lock
resource: unsafe { &*value.get() },
borrow: atomic_borrow,
}
} else {
panic!(
"Failed to acquire shared lock on resource: {}",
std::any::type_name::<T>()
);
}
} }
} }
@ -454,9 +466,24 @@ pub struct ResourceRefMut<'a, T: 'static> {
impl<'a, T: 'static> ResourceRefMut<'a, T> { impl<'a, T: 'static> ResourceRefMut<'a, T> {
/// Creates a new entity component mutable borrow /// Creates a new entity component mutable borrow
pub fn new(resource: &'a mut T, borrow: &'a AtomicBorrow) -> Self { fn new(
borrow.borrow_mut(); StoredResource {
Self { resource, borrow } value,
atomic_borrow,
}: &'a StoredResource<T>,
) -> Self {
if atomic_borrow.borrow_mut() {
Self {
// Safe because we acquired the lock
resource: unsafe { &mut *value.get() },
borrow: atomic_borrow,
}
} else {
panic!(
"Failed to acquire exclusive lock on resource: {}",
std::any::type_name::<T>()
);
}
} }
} }