Skip to content

Commit d4586ea

Browse files
authored
Merge pull request #163 from madsmtm/soundness-fixes
Small soundness fixes and code cleanup
2 parents 0e10639 + 8c38606 commit d4586ea

File tree

20 files changed

+176
-132
lines changed

20 files changed

+176
-132
lines changed

block2/src/global.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,10 @@ where
8383
type Target = Block<A, R>;
8484

8585
fn deref(&self) -> &Self::Target {
86+
let ptr: *const Self = self;
87+
let ptr: *const Block<A, R> = ptr.cast();
8688
// TODO: SAFETY
87-
unsafe { &*(self as *const Self as *const Block<A, R>) }
89+
unsafe { ptr.as_ref().unwrap_unchecked() }
8890
}
8991
}
9092

block2/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,10 @@ impl<A, R, F> Deref for ConcreteBlock<A, R, F> {
468468
type Target = Block<A, R>;
469469

470470
fn deref(&self) -> &Self::Target {
471-
unsafe { &*(self as *const Self as *const Block<A, R>) }
471+
let ptr: *const Self = self;
472+
let ptr: *const Block<A, R> = ptr.cast();
473+
// TODO: SAFETY
474+
unsafe { ptr.as_ref().unwrap_unchecked() }
472475
}
473476
}
474477

objc2-foundation/src/array.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,13 @@ unsafe fn from_refs<T: Message + ?Sized>(cls: &Class, refs: &[&T]) -> *mut Objec
5757
}
5858
}
5959

60-
impl<T: Message, O: Ownership> NSArray<T, O> {
60+
impl<T: Message> NSArray<T, Shared> {
6161
unsafe_def_fn! {
62-
/// The `NSArray` itself (length and number of items) is always immutable,
63-
/// but we would like to know when we're the only owner of the array, to
64-
/// allow mutation of the array's items.
65-
pub fn new -> O;
62+
pub fn new -> Shared;
6663
}
64+
}
6765

66+
impl<T: Message, O: Ownership> NSArray<T, O> {
6867
#[doc(alias = "count")]
6968
pub fn len(&self) -> usize {
7069
unsafe { msg_send![self, count] }
@@ -103,6 +102,9 @@ impl<T: Message, O: Ownership> NSArray<T, O> {
103102
}
104103
}
105104

105+
// The `NSArray` itself (length and number of items) is always immutable,
106+
// but we would like to know when we're the only owner of the array, to
107+
// allow mutation of the array's items.
106108
pub fn from_vec(vec: Vec<Id<T, O>>) -> Id<Self, O> {
107109
unsafe { Id::new(from_refs(Self::class(), vec.as_slice_ref()).cast()).unwrap() }
108110
}
@@ -204,8 +206,8 @@ impl<T: Message, O: Ownership> Index<usize> for NSArray<T, O> {
204206
}
205207
}
206208

207-
impl<T: Message, O: Ownership> DefaultId for NSArray<T, O> {
208-
type Ownership = O;
209+
impl<T: Message> DefaultId for NSArray<T, Shared> {
210+
type Ownership = Shared;
209211

210212
#[inline]
211213
fn default_id() -> Id<Self, Self::Ownership> {
@@ -308,7 +310,7 @@ impl<T: Message, O: Ownership> NSMutableArray<T, O> {
308310
// Bring back a reference to the closure.
309311
// Guaranteed to be unique, we gave `sortUsingFunction` unique is
310312
// ownership, and that method only runs one function at a time.
311-
let closure: &mut F = unsafe { &mut *(context as *mut F) };
313+
let closure: &mut F = unsafe { (context as *mut F).as_mut().unwrap_unchecked() };
312314

313315
NSComparisonResult::from((*closure)(obj1, obj2))
314316
}
@@ -407,9 +409,15 @@ mod tests {
407409
unsafe { msg_send![obj, retainCount] }
408410
}
409411

412+
#[test]
413+
fn test_two_empty() {
414+
let _empty_array1 = NSArray::<NSObject, _>::new();
415+
let _empty_array2 = NSArray::<NSObject, _>::new();
416+
}
417+
410418
#[test]
411419
fn test_len() {
412-
let empty_array = NSArray::<NSObject, Owned>::new();
420+
let empty_array = NSArray::<NSObject, _>::new();
413421
assert_eq!(empty_array.len(), 0);
414422

415423
let array = sample_array(4);
@@ -450,7 +458,7 @@ mod tests {
450458
assert_eq!(array.first(), array.get(0));
451459
assert_eq!(array.last(), array.get(3));
452460

453-
let empty_array = <NSArray<NSObject, Owned>>::new();
461+
let empty_array = <NSArray<NSObject, Shared>>::new();
454462
assert!(empty_array.first().is_none());
455463
assert!(empty_array.last().is_none());
456464
}

objc2-foundation/src/data.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ impl NSData {
5353

5454
pub fn bytes(&self) -> &[u8] {
5555
let ptr: *const c_void = unsafe { msg_send![self, bytes] };
56+
let ptr: *const u8 = ptr.cast();
5657
// The bytes pointer may be null for length zero
5758
if ptr.is_null() {
5859
&[]
5960
} else {
60-
unsafe { slice::from_raw_parts(ptr as *const u8, self.len()) }
61+
unsafe { slice::from_raw_parts(ptr, self.len()) }
6162
}
6263
}
6364

@@ -172,11 +173,12 @@ impl NSMutableData {
172173
#[doc(alias = "mutableBytes")]
173174
pub fn bytes_mut(&mut self) -> &mut [u8] {
174175
let ptr = self.raw_bytes_mut();
176+
let ptr: *mut u8 = ptr.cast();
175177
// The bytes pointer may be null for length zero
176178
if ptr.is_null() {
177179
&mut []
178180
} else {
179-
unsafe { slice::from_raw_parts_mut(ptr as *mut u8, self.len()) }
181+
unsafe { slice::from_raw_parts_mut(ptr, self.len()) }
180182
}
181183
}
182184

@@ -188,7 +190,7 @@ impl NSMutableData {
188190

189191
#[doc(alias = "appendBytes:length:")]
190192
pub fn extend_from_slice(&mut self, bytes: &[u8]) {
191-
let bytes_ptr = bytes.as_ptr() as *const c_void;
193+
let bytes_ptr: *const c_void = bytes.as_ptr().cast();
192194
unsafe { msg_send![self, appendBytes: bytes_ptr, length: bytes.len()] }
193195
}
194196

@@ -201,7 +203,7 @@ impl NSMutableData {
201203
let range = NSRange::from(range);
202204
// No need to verify the length of the range here,
203205
// `replaceBytesInRange:` just zero-fills if out of bounds.
204-
let ptr = bytes.as_ptr() as *const c_void;
206+
let ptr: *const c_void = bytes.as_ptr().cast();
205207
unsafe {
206208
msg_send![
207209
self,
@@ -312,7 +314,7 @@ impl DefaultId for NSMutableData {
312314
}
313315

314316
unsafe fn data_with_bytes(cls: &Class, bytes: &[u8]) -> *mut Object {
315-
let bytes_ptr = bytes.as_ptr() as *const c_void;
317+
let bytes_ptr: *const c_void = bytes.as_ptr().cast();
316318
unsafe {
317319
let obj: *mut Object = msg_send![cls, alloc];
318320
msg_send![
@@ -333,18 +335,19 @@ unsafe fn data_from_vec(cls: &Class, bytes: Vec<u8>) -> *mut Object {
333335

334336
let dealloc = ConcreteBlock::new(move |bytes: *mut c_void, len: usize| unsafe {
335337
// Recreate the Vec and let it drop
336-
let _ = Vec::from_raw_parts(bytes as *mut u8, len, capacity);
338+
let _ = Vec::<u8>::from_raw_parts(bytes.cast(), len, capacity);
337339
});
338340
let dealloc = dealloc.copy();
339341
let dealloc: &Block<(*mut c_void, usize), ()> = &dealloc;
340342

341343
let mut bytes = ManuallyDrop::new(bytes);
344+
let bytes_ptr: *mut c_void = bytes.as_mut_ptr().cast();
342345

343346
unsafe {
344347
let obj: *mut Object = msg_send![cls, alloc];
345348
msg_send![
346349
obj,
347-
initWithBytesNoCopy: bytes.as_mut_ptr() as *mut c_void,
350+
initWithBytesNoCopy: bytes_ptr,
348351
length: bytes.len(),
349352
deallocator: dealloc,
350353
]

objc2-foundation/src/enumerator.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl<'a, C: NSFastEnumeration + ?Sized> Iterator for NSFastEnumerator<'a, C> {
159159
unsafe {
160160
let obj = *self.ptr;
161161
self.ptr = self.ptr.offset(1);
162-
Some(&*obj)
162+
Some(obj.as_ref().unwrap_unchecked())
163163
}
164164
}
165165
}
@@ -172,25 +172,25 @@ mod tests {
172172

173173
#[test]
174174
fn test_enumerator() {
175-
let vec = (0u32..4).map(NSValue::new).collect();
175+
let vec = (0usize..4).map(NSValue::new).collect();
176176
let array = NSArray::from_vec(vec);
177177

178178
let enumerator = array.iter();
179179
assert_eq!(enumerator.count(), 4);
180180

181181
let enumerator = array.iter();
182-
assert!(enumerator.enumerate().all(|(i, obj)| obj.get() == i as u32));
182+
assert!(enumerator.enumerate().all(|(i, obj)| obj.get() == i));
183183
}
184184

185185
#[test]
186186
fn test_fast_enumerator() {
187-
let vec = (0u32..4).map(NSValue::new).collect();
187+
let vec = (0usize..4).map(NSValue::new).collect();
188188
let array = NSArray::from_vec(vec);
189189

190190
let enumerator = array.iter_fast();
191191
assert_eq!(enumerator.count(), 4);
192192

193193
let enumerator = array.iter_fast();
194-
assert!(enumerator.enumerate().all(|(i, obj)| obj.get() == i as u32));
194+
assert!(enumerator.enumerate().all(|(i, obj)| obj.get() == i));
195195
}
196196
}

objc2-foundation/src/macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ macro_rules! object {
178178
impl<$($t: ::core::cmp::PartialEq $(+ $b)?),*> ::core::cmp::PartialEq for $name<$($t),*> {
179179
#[inline]
180180
fn eq(&self, other: &Self) -> bool {
181-
self.is_equal(&*other)
181+
self.is_equal(other.as_ref())
182182
}
183183
}
184184

objc2-foundation/src/string.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl NSString {
140140
//
141141
// https://developer.apple.com/documentation/foundation/nsstring/1411189-utf8string?language=objc
142142
let bytes: *const c_char = unsafe { msg_send![self, UTF8String] };
143-
let bytes = bytes as *const u8;
143+
let bytes: *const u8 = bytes.cast();
144144
let len = self.len();
145145

146146
// SAFETY:
@@ -199,7 +199,7 @@ impl NSString {
199199
}
200200

201201
pub(crate) fn from_str(cls: &Class, string: &str) -> *mut Object {
202-
let bytes = string.as_ptr() as *const c_void;
202+
let bytes: *const c_void = string.as_ptr().cast();
203203
unsafe {
204204
let obj: *mut Object = msg_send![cls, alloc];
205205
msg_send![
@@ -276,6 +276,7 @@ impl fmt::Display for NSString {
276276
mod tests {
277277
use super::*;
278278
use alloc::format;
279+
use core::ptr;
279280

280281
#[cfg(feature = "gnustep-1-7")]
281282
#[test]
@@ -365,11 +366,10 @@ mod tests {
365366
fn test_copy_nsstring_is_same() {
366367
let string1 = NSString::from_str("Hello, world!");
367368
let string2 = string1.copy();
368-
369-
let s1: *const NSString = &*string1;
370-
let s2: *const NSString = &*string2;
371-
372-
assert_eq!(s1, s2, "Cloned NSString didn't have the same address");
369+
assert!(
370+
ptr::eq(&*string1, &*string2),
371+
"Cloned NSString didn't have the same address"
372+
);
373373
}
374374

375375
#[test]

objc2-foundation/src/value.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<T: 'static + Copy + Encode> NSValue<T> {
5252
/// The user must ensure that the inner value is properly initialized.
5353
pub unsafe fn get_unchecked(&self) -> T {
5454
let mut value = MaybeUninit::<T>::uninit();
55-
let ptr = value.as_mut_ptr() as *mut c_void;
55+
let ptr: *mut c_void = value.as_mut_ptr().cast();
5656
let _: () = unsafe { msg_send![self, getValue: ptr] };
5757
unsafe { value.assume_init() }
5858
}
@@ -64,7 +64,8 @@ impl<T: 'static + Copy + Encode> NSValue<T> {
6464

6565
pub fn new(value: T) -> Id<Self, Shared> {
6666
let cls = Self::class();
67-
let bytes = &value as *const T as *const c_void;
67+
let bytes: *const T = &value;
68+
let bytes: *const c_void = bytes.cast();
6869
let encoding = CString::new(T::ENCODING.to_string()).unwrap();
6970
unsafe {
7071
let obj: *mut Self = msg_send![cls, alloc];

objc2/examples/talk_to_me.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ fn main() {
1414
const UTF8_ENCODING: NSUInteger = 4;
1515

1616
let string: *const Object = unsafe { msg_send![class!(NSString), alloc] };
17+
let text_ptr: *const c_void = text.as_ptr().cast();
1718
let string = unsafe {
1819
msg_send![
1920
string,
20-
initWithBytes: text.as_ptr() as *const c_void,
21+
initWithBytes: text_ptr,
2122
length: text.len(),
2223
encoding: UTF8_ENCODING,
2324
]

objc2/src/cache.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ impl CachedSel {
2727
// `Relaxed` should be fine since `sel_registerName` is thread-safe.
2828
let ptr = self.ptr.load(Ordering::Relaxed);
2929
if ptr.is_null() {
30-
let ptr = unsafe { ffi::sel_registerName(name.as_ptr() as *const _) };
31-
self.ptr.store(ptr as *mut _, Ordering::Relaxed);
32-
unsafe { Sel::from_ptr(ptr as *const _) }
30+
let ptr: *const c_void = unsafe { ffi::sel_registerName(name.as_ptr().cast()).cast() };
31+
self.ptr.store(ptr as *mut c_void, Ordering::Relaxed);
32+
unsafe { Sel::from_ptr(ptr) }
3333
} else {
3434
unsafe { Sel::from_ptr(ptr) }
3535
}
@@ -57,12 +57,12 @@ impl CachedClass {
5757
pub unsafe fn get(&self, name: &str) -> Option<&'static Class> {
5858
// `Relaxed` should be fine since `objc_getClass` is thread-safe.
5959
let ptr = self.ptr.load(Ordering::Relaxed);
60-
if ptr.is_null() {
61-
let cls = unsafe { ffi::objc_getClass(name.as_ptr() as *const _) } as *const Class;
62-
self.ptr.store(cls as *mut _, Ordering::Relaxed);
63-
unsafe { cls.as_ref() }
60+
if let Some(cls) = unsafe { ptr.as_ref() } {
61+
Some(cls)
6462
} else {
65-
Some(unsafe { &*ptr })
63+
let ptr: *const Class = unsafe { ffi::objc_getClass(name.as_ptr().cast()) }.cast();
64+
self.ptr.store(ptr as *mut Class, Ordering::Relaxed);
65+
unsafe { ptr.as_ref() }
6666
}
6767
}
6868
}

0 commit comments

Comments
 (0)