Skip to content

Commit 69b5047

Browse files
committed
Undo making Owned and Retained take references.
See f52bc56, but that change made it very easy to create unbounded references, or create two aliasing mutable references.
1 parent 7147f9f commit 69b5047

File tree

2 files changed

+31
-20
lines changed

2 files changed

+31
-20
lines changed

src/rc/owned.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::runtime::{self, Object};
2121
///
2222
/// This does not implement [`Clone`], but [`Retained`] has a [`From`]
2323
/// implementation to convert from this, so you can easily reliquish ownership
24-
/// and work with a normal [`Retained`] pointer.
24+
/// and work with a clonable [`Retained`] pointer.
2525
///
2626
/// ```no_run
2727
/// let obj: Owned<T> = ...;
@@ -57,9 +57,13 @@ impl<T> Owned<T> {
5757
/// # Safety
5858
///
5959
/// The caller must ensure that there are no other pointers or references
60-
/// to the same object, and the given reference is not be used afterwards.
60+
/// to the same object, and the given pointer is not be used afterwards.
6161
///
62-
/// Additionally, the given object reference must have +1 retain count.
62+
/// Additionally, the given object pointer must have +1 retain count.
63+
///
64+
/// And lastly, the object pointer must be valid as a mutable reference
65+
/// (non-null, aligned, dereferencable, initialized and upholds aliasing
66+
/// rules, see the [`std::ptr`] module for more information).
6367
///
6468
/// # Example
6569
///
@@ -69,15 +73,13 @@ impl<T> Owned<T> {
6973
/// // Or in this case simply just:
7074
/// let obj: Owned<Object> = unsafe { Owned::new(msg_send![cls, new]) };
7175
/// ```
72-
///
73-
/// TODO: Something about there not being other references.
74-
// Note: The fact that we take a `&mut` here is more of a lint; the lifetime
75-
// information is lost, so whatever produced the reference can still be
76-
// mutated or aliased afterwards.
7776
#[inline]
78-
pub unsafe fn new(obj: &mut T) -> Self {
77+
// Note: We don't take a mutable reference as a parameter since it would
78+
// be too easy to accidentally create two aliasing mutable references.
79+
pub unsafe fn new(ptr: *mut T) -> Self {
7980
Self {
80-
ptr: obj.into(),
81+
// SAFETY: Upheld by the caller
82+
ptr: NonNull::new_unchecked(ptr),
8183
phantom: PhantomData,
8284
}
8385
}

src/rc/retained.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,17 @@ impl<T> Retained<T> {
9292
///
9393
/// The caller must ensure the given object reference has +1 retain count.
9494
///
95-
/// Additionally, there must be no [`Owned`] pointers to the same object.
95+
/// Additionally, there must be no [`Owned`] pointers or mutable
96+
/// references to the same object.
9697
///
97-
/// TODO: Something about there not being any mutable references.
98+
/// And lastly, the object pointer must be valid as a reference (non-null,
99+
/// aligned, dereferencable, initialized and upholds aliasing rules, see
100+
/// the [`std::ptr`] module for more information).
98101
#[inline]
99-
pub unsafe fn new(obj: &T) -> Self {
102+
pub unsafe fn new(ptr: *const T) -> Self {
100103
Self {
101-
ptr: obj.into(),
104+
// SAFETY: Upheld by the caller
105+
ptr: NonNull::new_unchecked(ptr as *mut T),
102106
phantom: PhantomData,
103107
}
104108
}
@@ -117,6 +121,10 @@ impl<T> Retained<T> {
117121
///
118122
/// The caller must ensure that there are no [`Owned`] pointers to the
119123
/// same object.
124+
///
125+
/// Additionally, the object pointer must be valid as a reference
126+
/// (non-null, aligned, dereferencable, initialized and upholds aliasing
127+
/// rules, see the [`std::ptr`] module for more information).
120128
//
121129
// So this would be illegal:
122130
// ```rust
@@ -131,12 +139,14 @@ impl<T> Retained<T> {
131139
#[doc(alias = "objc_retain")]
132140
// Inlined since it's `objc_retain` that does the work.
133141
#[cfg_attr(debug_assertions, inline)]
134-
pub unsafe fn retain(obj: &T) -> Self {
142+
pub unsafe fn retain(ptr: *const T) -> Self {
135143
// SAFETY: The caller upholds that the pointer is valid
136-
let rtn = runtime::objc_retain(obj as *const T as *mut Object);
137-
debug_assert_eq!(rtn, obj as *const T as *mut Object);
144+
let rtn = runtime::objc_retain(ptr as *mut Object) as *const T;
145+
debug_assert_eq!(rtn, ptr);
138146
Self {
139-
ptr: obj.into(),
147+
// SAFETY: Non-null upheld by the caller and `objc_retain` always
148+
// returns the same pointer.
149+
ptr: NonNull::new_unchecked(rtn as *mut T),
140150
phantom: PhantomData,
141151
}
142152
}
@@ -234,7 +244,7 @@ impl<T> Clone for Retained<T> {
234244
#[inline]
235245
fn clone(&self) -> Self {
236246
// SAFETY: The `ptr` is guaranteed to be valid
237-
unsafe { Self::retain(&*self) }
247+
unsafe { Self::retain(self.as_ptr()) }
238248
}
239249
}
240250

@@ -312,7 +322,6 @@ impl<T> From<Owned<T>> for Retained<T> {
312322
#[cfg(test)]
313323
mod tests {
314324
use core::mem::size_of;
315-
use core::ptr::NonNull;
316325

317326
use super::Retained;
318327
use crate::runtime::Object;

0 commit comments

Comments
 (0)