Skip to content

Commit dbddcb8

Browse files
authored
Merge pull request #150 from madsmtm/msg-send-receiver-soundness
Change how mutability in `msg_send!` is done
2 parents 5bd6979 + 2beef61 commit dbddcb8

29 files changed

+321
-138
lines changed

objc2-foundation/examples/custom_class.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ fn main() {
7070

7171
obj.set_number(7);
7272
println!("Number: {}", unsafe {
73-
let number: u32 = msg_send![obj, number];
73+
let number: u32 = msg_send![&obj, number];
7474
number
7575
});
7676

7777
unsafe {
78-
let _: () = msg_send![obj, setNumber: 12u32];
78+
let _: () = msg_send![&mut obj, setNumber: 12u32];
7979
}
8080
println!("Number: {}", obj.number());
8181
}

objc2-foundation/src/array.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -272,15 +272,18 @@ impl<T: Message, O: Ownership> NSMutableArray<T, O> {
272272
obj
273273
}
274274

275+
fn remove_last(&mut self) {
276+
unsafe { msg_send![self, removeLastObject] }
277+
}
278+
275279
#[doc(alias = "removeLastObject")]
276280
pub fn pop(&mut self) -> Option<Id<T, O>> {
277-
self.last().map(|obj| {
278-
let obj = unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() };
279-
unsafe {
280-
let _: () = msg_send![self, removeLastObject];
281-
}
282-
obj
283-
})
281+
self.last()
282+
.map(|obj| unsafe { Id::retain(obj as *const T as *mut T).unwrap_unchecked() })
283+
.map(|obj| {
284+
self.remove_last();
285+
obj
286+
})
284287
}
285288

286289
#[doc(alias = "removeAllObjects")]

objc2-foundation/src/attributed_string.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,14 @@ mod tests {
153153
let s2 = s1.copy();
154154
// NSAttributedString performs this optimization in GNUStep's runtime,
155155
// but not in Apple's; so we don't test for it!
156-
// assert_eq!(s1.as_ptr(), s2.as_ptr());
156+
// assert_eq!(Id::as_ptr(&s1), Id::as_ptr(&s2));
157157
assert!(s2.is_kind_of(NSAttributedString::class()));
158158

159159
let s3 = s1.mutable_copy();
160-
assert_ne!(s1.as_ptr(), s3.as_ptr() as *mut NSAttributedString);
160+
assert_ne!(
161+
Id::as_ptr(&s1),
162+
Id::as_ptr(&s3) as *const NSAttributedString
163+
);
161164
assert!(s3.is_kind_of(NSMutableAttributedString::class()));
162165
}
163166
}

objc2-foundation/src/data.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,14 @@ impl NSMutableData {
154154

155155
/// Mutation methods
156156
impl NSMutableData {
157+
// Helps with reborrowing issue
158+
fn raw_bytes_mut(&mut self) -> *mut c_void {
159+
unsafe { msg_send![self, mutableBytes] }
160+
}
161+
157162
#[doc(alias = "mutableBytes")]
158163
pub fn bytes_mut(&mut self) -> &mut [u8] {
159-
let ptr: *mut c_void = unsafe { msg_send![self, mutableBytes] };
164+
let ptr = self.raw_bytes_mut();
160165
// The bytes pointer may be null for length zero
161166
if ptr.is_null() {
162167
&mut []

objc2-foundation/src/dictionary.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl<K: Message, V: Message> NSDictionary<K, V> {
129129

130130
pub fn into_values_array(dict: Id<Self, Owned>) -> Id<NSArray<V, Owned>, Shared> {
131131
unsafe {
132-
let vals = msg_send![dict, allValues];
132+
let vals = msg_send![&dict, allValues];
133133
Id::retain_autoreleased(vals).unwrap()
134134
}
135135
}

objc2-foundation/src/enumerator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl<'a, T: Message> Iterator for NSEnumerator<'a, T> {
3333
type Item = &'a T;
3434

3535
fn next(&mut self) -> Option<&'a T> {
36-
unsafe { msg_send![self.id, nextObject] }
36+
unsafe { msg_send![&mut self.id, nextObject] }
3737
}
3838
}
3939

objc2-foundation/src/mutable_attributed_string.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,14 @@ mod tests {
9090
fn test_copy() {
9191
let s1 = NSMutableAttributedString::from_nsstring(&NSString::from_str("abc"));
9292
let s2 = s1.copy();
93-
assert_ne!(s1.as_ptr() as *const NSAttributedString, s2.as_ptr());
93+
assert_ne!(
94+
Id::as_ptr(&s1) as *const NSAttributedString,
95+
Id::as_ptr(&s2)
96+
);
9497
assert!(s2.is_kind_of(NSAttributedString::class()));
9598

9699
let s3 = s1.mutable_copy();
97-
assert_ne!(s1.as_ptr(), s3.as_ptr());
100+
assert_ne!(Id::as_ptr(&s1), Id::as_ptr(&s3));
98101
assert!(s3.is_kind_of(NSMutableAttributedString::class()));
99102
}
100103
}

objc2-foundation/src/mutable_string.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ mod tests {
200200
fn test_copy() {
201201
let s1 = NSMutableString::from_str("abc");
202202
let s2 = s1.copy();
203-
assert_ne!(s1.as_ptr(), s2.as_ptr() as *mut NSMutableString);
203+
assert_ne!(Id::as_ptr(&s1), Id::as_ptr(&s2) as *const NSMutableString);
204204
assert!(s2.is_kind_of(NSString::class()));
205205

206206
let s3 = s1.mutable_copy();
207-
assert_ne!(s1.as_ptr(), s3.as_ptr());
207+
assert_ne!(Id::as_ptr(&s1), Id::as_ptr(&s3));
208208
assert!(s3.is_kind_of(NSMutableString::class()));
209209
}
210210
}

objc2-foundation/src/string.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,11 +346,11 @@ mod tests {
346346
let s1 = NSString::from_str("abc");
347347
let s2 = s1.copy();
348348
// An optimization that NSString makes, since it is immutable
349-
assert_eq!(s1.as_ptr(), s2.as_ptr());
349+
assert_eq!(Id::as_ptr(&s1), Id::as_ptr(&s2));
350350
assert!(s2.is_kind_of(NSString::class()));
351351

352352
let s3 = s1.mutable_copy();
353-
assert_ne!(s1.as_ptr(), s3.as_ptr() as *mut NSString);
353+
assert_ne!(Id::as_ptr(&s1), Id::as_ptr(&s3) as *const NSString);
354354
assert!(s3.is_kind_of(NSMutableString::class()));
355355
}
356356

objc2-foundation/src/value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ mod tests {
177177
fn test_value_nsrange() {
178178
let val = NSValue::new(NSRange::from(1..2));
179179
assert!(NSRange::ENCODING.equivalent_to_str(val.encoding().unwrap()));
180-
let range: NSRange = unsafe { objc2::msg_send![val, rangeValue] };
180+
let range: NSRange = unsafe { objc2::msg_send![&val, rangeValue] };
181181
assert_eq!(range, NSRange::from(1..2));
182182
// NSValue -getValue is broken on GNUStep for some types
183183
#[cfg(not(feature = "gnustep-1-7"))]

objc2/CHANGELOG.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1111
upgrading easier.
1212
* Allow using `From`/`TryFrom` to convert between `rc::Id` and `rc::WeakId`.
1313
* Added `Bool::as_bool` (more descriptive name than `Bool::is_true`).
14-
* Added convenience method `Id::as_ptr`.
14+
* Added convenience method `Id::as_ptr` and `Id::as_mut_ptr`.
1515
* The `objc2-encode` dependency is now exposed as `objc2::encode`.
1616
* Added `Id::retain_autoreleased` to allow following Cocoas memory management
1717
rules more efficiently.
@@ -38,6 +38,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
3838
`ClassBuilder::add_method`.
3939
* Renamed `ClassDecl` and `ProtocolDecl` to `ClassBuilder` and
4040
`ProtocolBuilder`. The old names are kept as deprecated aliases.
41+
* **BREAKING**: Changed how `msg_send!` works wrt. capturing its arguments.
42+
43+
This will require changes to your code wherever you used `Id`, for example:
44+
```rust
45+
// Before
46+
let obj: Id<Object, Owned> = ...;
47+
let p: i32 = unsafe { msg_send![obj, parameter] };
48+
let _: () = unsafe { msg_send![obj, setParameter: p + 1] };
49+
// After
50+
let mut obj: Id<Object, Owned> = ...;
51+
let p: i32 = unsafe { msg_send![&obj, parameter] };
52+
let _: () = unsafe { msg_send![&mut obj, setParameter: p + 1] };
53+
```
54+
55+
Notice that we now clearly pass `obj` by reference, and therein also
56+
communicate the mutability of the object (in the first case, immutable, and
57+
in the second, mutable).
58+
59+
If you previously used `*mut Object` or `&Object` as the receiver, message
60+
sending should work exactly as before.
4161

4262
### Fixed
4363
* Properly sealed the `MessageArguments` trait (it already had a hidden

objc2/benches/autorelease.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ fn new_nsdata() -> Id<Object, Shared> {
6161
unsafe { Id::new(obj).unwrap_unchecked() }
6262
}
6363

64-
fn new_leaked_nsdata() -> *mut Object {
65-
ManuallyDrop::new(new_nsdata()).as_ptr()
64+
fn new_leaked_nsdata() -> *const Object {
65+
Id::as_ptr(&*ManuallyDrop::new(new_nsdata()))
6666
}
6767

68-
fn autoreleased_nsdata() -> *mut Object {
68+
fn autoreleased_nsdata() -> *const Object {
6969
// let bytes_ptr = BYTES.as_ptr() as *const c_void;
7070
// unsafe {
7171
// msg_send![
@@ -83,20 +83,20 @@ fn new_nsstring() -> Id<Object, Shared> {
8383
unsafe { Id::new(obj).unwrap_unchecked() }
8484
}
8585

86-
fn new_leaked_nsstring() -> *mut Object {
87-
ManuallyDrop::new(new_nsstring()).as_ptr()
86+
fn new_leaked_nsstring() -> *const Object {
87+
Id::as_ptr(&*ManuallyDrop::new(new_nsstring()))
8888
}
8989

90-
fn autoreleased_nsstring() -> *mut Object {
90+
fn autoreleased_nsstring() -> *const Object {
9191
// unsafe { msg_send![class!(NSString), string] }
9292
unsafe { msg_send![new_leaked_nsstring(), autorelease] }
9393
}
9494

95-
fn retain_autoreleased(obj: *mut Object) -> Id<Object, Shared> {
96-
unsafe { Id::retain_autoreleased(obj.cast()).unwrap_unchecked() }
95+
fn retain_autoreleased(obj: *const Object) -> Id<Object, Shared> {
96+
unsafe { Id::retain_autoreleased((obj as *mut Object).cast()).unwrap_unchecked() }
9797
}
9898

99-
fn autoreleased_nsdata_pool_cleanup() -> *mut Object {
99+
fn autoreleased_nsdata_pool_cleanup() -> *const Object {
100100
autoreleasepool(|_| autoreleased_nsdata())
101101
}
102102

@@ -108,7 +108,7 @@ fn autoreleased_nsdata_fast_caller_cleanup_pool_cleanup() -> Id<Object, Shared>
108108
autoreleasepool(|_| retain_autoreleased(autoreleased_nsdata()))
109109
}
110110

111-
fn autoreleased_nsstring_pool_cleanup() -> *mut Object {
111+
fn autoreleased_nsstring_pool_cleanup() -> *const Object {
112112
autoreleasepool(|_| autoreleased_nsstring())
113113
}
114114

objc2/examples/introspection.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ fn main() {
4242
}
4343

4444
// Invoke a method on the object
45-
let hash: usize = unsafe { msg_send![obj, hash] };
45+
let hash: usize = unsafe { msg_send![&obj, hash] };
4646
println!("NSObject hash: {}", hash);
4747
}

objc2/examples/talk_to_me.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ fn main() {
3131
let utterance: *mut Object = unsafe { msg_send![utterance, initWithString: &*string] };
3232
let utterance: Id<Object, Owned> = unsafe { Id::new(utterance).unwrap() };
3333

34-
// let _: () = unsafe { msg_send![utterance, setVolume: 90.0f32 };
35-
// let _: () = unsafe { msg_send![utterance, setRate: 0.50f32 };
36-
// let _: () = unsafe { msg_send![utterance, setPitchMultiplier: 0.80f32 };
34+
// let _: () = unsafe { msg_send![&utterance, setVolume: 90.0f32 };
35+
// let _: () = unsafe { msg_send![&utterance, setRate: 0.50f32 };
36+
// let _: () = unsafe { msg_send![&utterance, setPitchMultiplier: 0.80f32 };
3737

38-
let _: () = unsafe { msg_send![synthesizer, speakUtterance: &*utterance] };
38+
let _: () = unsafe { msg_send![&synthesizer, speakUtterance: &*utterance] };
3939
}

objc2/src/declare.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,9 @@ mod tests {
415415
#[test]
416416
fn test_custom_class() {
417417
// Registering the custom class is in test_utils
418-
let obj = test_utils::custom_object();
419-
let _: () = unsafe { msg_send![obj, setFoo: 13u32] };
420-
let result: u32 = unsafe { msg_send![obj, foo] };
418+
let mut obj = test_utils::custom_object();
419+
let _: () = unsafe { msg_send![&mut obj, setFoo: 13u32] };
420+
let result: u32 = unsafe { msg_send![&obj, foo] };
421421
assert_eq!(result, 13);
422422
}
423423

objc2/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
//! };
4343
//!
4444
//! // Usage
45-
//! let hash: NSUInteger = unsafe { msg_send![obj, hash] };
46-
//! let is_kind = unsafe { msg_send_bool![obj, isKindOfClass: cls] };
45+
//! let hash: NSUInteger = unsafe { msg_send![&obj, hash] };
46+
//! let is_kind = unsafe { msg_send_bool![&obj, isKindOfClass: cls] };
4747
//! assert!(is_kind);
4848
//! ```
4949
//!

0 commit comments

Comments
 (0)