Skip to content

Commit 98e111c

Browse files
authored
Merge pull request #184 from madsmtm/error-handling
Improve message verification and error handling
2 parents 185201d + da39ecf commit 98e111c

File tree

14 files changed

+291
-210
lines changed

14 files changed

+291
-210
lines changed

objc2/CHANGELOG.md

+10-3
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
3333
objects.
3434
* Added `Object::ivar_ptr` to allow direct access to instance variables
3535
through `&Object`.
36+
* Added `VerificationError` as more specific return type from
37+
`Class::verify_sel`.
3638

3739
### Changed
38-
* **BREAKING:** `Sel` is now required to be non-null, which means that you
40+
* **BREAKING**: `Sel` is now required to be non-null, which means that you
3941
have to ensure that any selectors you receive from method calls are
4042
non-null before using them.
4143
* **BREAKING**: `ClassBuilder::root` is now generic over the function pointer,
4244
meaning you will have to coerce initializer functions to pointers like in
4345
`ClassBuilder::add_method` before you can use it.
44-
* **BREAKING**: Moved `MessageReceiver::verify_message` to `Class::verify_sel`.
46+
* **BREAKING**: Moved `MessageReceiver::verify_message` to `Class::verify_sel`
47+
and changed return type.
48+
* Improved debug output with `verify_message` feature enabled.
49+
* **BREAKING**: Changed `MessageReceiver::send_message` to panic instead of
50+
returning an error.
4551

4652
### Removed
47-
* **BREAKING:** Removed the `Sel::from_ptr` and `Sel::as_ptr` methods.
53+
* **BREAKING**: Removed the `Sel::from_ptr` and `Sel::as_ptr` methods.
54+
* **BREAKING**: Removed `MessageError`.
4855

4956

5057
## 0.3.0-beta.0 - 2022-06-13

objc2/src/__macro_helpers.rs

+34-25
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use crate::rc::{Id, Ownership};
22
use crate::runtime::{Class, Sel};
3-
use crate::{Message, MessageArguments, MessageError, MessageReceiver};
3+
use crate::{Message, MessageArguments, MessageReceiver};
44

55
pub use crate::cache::CachedClass;
66
pub use crate::cache::CachedSel;
77

88
pub use core::cell::UnsafeCell;
99
pub use core::option::Option::{self, None, Some};
1010
pub use core::primitive::{bool, str, u8};
11-
pub use core::result::Result::{Err, Ok};
1211
pub use core::{compile_error, concat, panic, stringify};
1312
#[cfg(feature = "objc2-proc-macros")]
1413
pub use objc2_proc_macros::__hash_idents;
@@ -48,24 +47,24 @@ pub struct RetainSemantics<
4847
> {}
4948

5049
pub trait MsgSendId<T, U> {
51-
unsafe fn send_message_id<A: MessageArguments>(
52-
obj: T,
53-
sel: Sel,
54-
args: A,
55-
) -> Result<Option<U>, MessageError>;
50+
unsafe fn send_message_id<A: MessageArguments>(obj: T, sel: Sel, args: A) -> Option<U>;
5651
}
5752

5853
// `new`
5954
impl<T: ?Sized + Message, O: Ownership> MsgSendId<&'_ Class, Id<T, O>>
6055
for RetainSemantics<true, false, false, false>
6156
{
6257
#[inline]
58+
#[track_caller]
6359
unsafe fn send_message_id<A: MessageArguments>(
6460
obj: &Class,
6561
sel: Sel,
6662
args: A,
67-
) -> Result<Option<Id<T, O>>, MessageError> {
68-
unsafe { MessageReceiver::send_message(obj, sel, args).map(|r| Id::new(r)) }
63+
) -> Option<Id<T, O>> {
64+
// SAFETY: Checked by caller
65+
let obj = unsafe { MessageReceiver::send_message(obj, sel, args) };
66+
// SAFETY: The selector is `new`, so this has +1 retain count
67+
unsafe { Id::new(obj) }
6968
}
7069
}
7170

@@ -74,12 +73,16 @@ impl<T: ?Sized + Message, O: Ownership> MsgSendId<&'_ Class, Id<T, O>>
7473
for RetainSemantics<false, true, false, false>
7574
{
7675
#[inline]
76+
#[track_caller]
7777
unsafe fn send_message_id<A: MessageArguments>(
7878
cls: &Class,
7979
sel: Sel,
8080
args: A,
81-
) -> Result<Option<Id<T, O>>, MessageError> {
82-
unsafe { MessageReceiver::send_message(cls, sel, args).map(|r| Id::new(r)) }
81+
) -> Option<Id<T, O>> {
82+
// SAFETY: Checked by caller
83+
let obj = unsafe { MessageReceiver::send_message(cls, sel, args) };
84+
// SAFETY: The selector is `alloc`, so this has +1 retain count
85+
unsafe { Id::new(obj) }
8386
}
8487
}
8588

@@ -88,19 +91,22 @@ impl<T: ?Sized + Message, O: Ownership> MsgSendId<Option<Id<T, O>>, Id<T, O>>
8891
for RetainSemantics<false, false, true, false>
8992
{
9093
#[inline]
94+
#[track_caller]
9195
unsafe fn send_message_id<A: MessageArguments>(
9296
obj: Option<Id<T, O>>,
9397
sel: Sel,
9498
args: A,
95-
) -> Result<Option<Id<T, O>>, MessageError> {
99+
) -> Option<Id<T, O>> {
96100
let ptr = Id::option_into_ptr(obj);
97101
// SAFETY: `ptr` may be null here, but that's fine since the return
98102
// is `*mut T`, which is one of the few types where messages to nil is
99103
// allowed.
100104
//
101105
// We do this for efficiency, to avoid having a branch after every
102106
// `alloc`, that the user did not intend.
103-
unsafe { MessageReceiver::send_message(ptr, sel, args).map(|r| Id::new(r)) }
107+
let obj = unsafe { MessageReceiver::send_message(ptr, sel, args) };
108+
// SAFETY: The selector is `init`, so this has +1 retain count
109+
unsafe { Id::new(obj) }
104110
}
105111
}
106112

@@ -109,12 +115,13 @@ impl<T: MessageReceiver, U: ?Sized + Message, O: Ownership> MsgSendId<T, Id<U, O
109115
for RetainSemantics<false, false, false, true>
110116
{
111117
#[inline]
112-
unsafe fn send_message_id<A: MessageArguments>(
113-
obj: T,
114-
sel: Sel,
115-
args: A,
116-
) -> Result<Option<Id<U, O>>, MessageError> {
117-
unsafe { MessageReceiver::send_message(obj, sel, args).map(|r| Id::new(r)) }
118+
#[track_caller]
119+
unsafe fn send_message_id<A: MessageArguments>(obj: T, sel: Sel, args: A) -> Option<Id<U, O>> {
120+
// SAFETY: Checked by caller
121+
let obj = unsafe { MessageReceiver::send_message(obj, sel, args) };
122+
// SAFETY: The selector is `copy` or `mutableCopy`, so this has +1
123+
// retain count
124+
unsafe { Id::new(obj) }
118125
}
119126
}
120127

@@ -123,14 +130,16 @@ impl<T: MessageReceiver, U: Message, O: Ownership> MsgSendId<T, Id<U, O>>
123130
for RetainSemantics<false, false, false, false>
124131
{
125132
#[inline]
126-
unsafe fn send_message_id<A: MessageArguments>(
127-
obj: T,
128-
sel: Sel,
129-
args: A,
130-
) -> Result<Option<Id<U, O>>, MessageError> {
133+
#[track_caller]
134+
unsafe fn send_message_id<A: MessageArguments>(obj: T, sel: Sel, args: A) -> Option<Id<U, O>> {
135+
// SAFETY: Checked by caller
136+
let obj = unsafe { MessageReceiver::send_message(obj, sel, args) };
131137
// All code between the message send and the `retain_autoreleased`
132138
// must be able to be optimized away for this to work.
133-
unsafe { MessageReceiver::send_message(obj, sel, args).map(|r| Id::retain_autoreleased(r)) }
139+
140+
// SAFETY: The selector is not `new`, `alloc`, `init`, `copy` nor
141+
// `mutableCopy`, so the object must be manually retained.
142+
unsafe { Id::retain_autoreleased(obj) }
134143
}
135144
}
136145

objc2/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ pub use objc_sys as ffi;
199199
#[doc(no_inline)]
200200
pub use objc2_encode::{Encode, EncodeArguments, Encoding, RefEncode};
201201

202-
pub use crate::message::{Message, MessageArguments, MessageError, MessageReceiver};
202+
pub use crate::message::{Message, MessageArguments, MessageReceiver};
203+
#[cfg(feature = "malloc")]
204+
pub use crate::verify::VerificationError;
203205

204206
#[macro_use]
205207
mod macros;

objc2/src/macros.rs

+13-32
Original file line numberDiff line numberDiff line change
@@ -455,45 +455,30 @@ macro_rules! __sel_inner {
455455
#[macro_export]
456456
macro_rules! msg_send {
457457
[super($obj:expr, $superclass:expr), $selector:ident $(,)?] => ({
458-
// Note: this import means that using these types inside `expr` will
459-
// generate an error. We won't bother with that (yet) though.
460-
use $crate::__macro_helpers::{Err, Ok, panic};
461458
let sel = $crate::sel!($selector);
462459
let result;
463-
match $crate::MessageReceiver::send_super_message($obj, $superclass, sel, ()) {
464-
Err(s) => panic!("{}", s),
465-
Ok(r) => result = r,
466-
}
460+
// Note: `sel` and `result` can be accessed from the `obj` and
461+
// `superclass` expressions - we won't (yet) bother with preventing
462+
// that though.
463+
result = $crate::MessageReceiver::send_super_message($obj, $superclass, sel, ());
467464
result
468465
});
469466
[super($obj:expr, $superclass:expr), $($selector:ident : $argument:expr $(,)?)+] => ({
470-
use $crate::__macro_helpers::{Err, Ok, panic};
471467
let sel = $crate::sel!($($selector :)+);
472468
let result;
473-
match $crate::MessageReceiver::send_super_message($obj, $superclass, sel, ($($argument,)+)) {
474-
Err(s) => panic!("{}", s),
475-
Ok(r) => result = r,
476-
}
469+
result = $crate::MessageReceiver::send_super_message($obj, $superclass, sel, ($($argument,)+));
477470
result
478471
});
479472
[$obj:expr, $selector:ident $(,)?] => ({
480-
use $crate::__macro_helpers::{Err, Ok, panic};
481473
let sel = $crate::sel!($selector);
482474
let result;
483-
match $crate::MessageReceiver::send_message($obj, sel, ()) {
484-
Err(s) => panic!("{}", s),
485-
Ok(r) => result = r,
486-
}
475+
result = $crate::MessageReceiver::send_message($obj, sel, ());
487476
result
488477
});
489478
[$obj:expr, $($selector:ident : $argument:expr $(,)?)+] => ({
490-
use $crate::__macro_helpers::{Err, Ok, panic};
491479
let sel = $crate::sel!($($selector :)+);
492480
let result;
493-
match $crate::MessageReceiver::send_message($obj, sel, ($($argument,)+)) {
494-
Err(s) => panic!("{}", s),
495-
Ok(r) => result = r,
496-
}
481+
result = $crate::MessageReceiver::send_message($obj, sel, ($($argument,)+));
497482
result
498483
});
499484
}
@@ -669,29 +654,25 @@ macro_rules! msg_send_id {
669654
[$obj:expr, $selector:ident $(,)?] => ({
670655
$crate::__msg_send_id_helper!(@verify $selector);
671656

672-
use $crate::__macro_helpers::{u8, Err, Ok, Option, panic, stringify};
657+
// Note: this import means that using these types inside `expr` may
658+
// generate an error. We won't (yet) bother with that though.
659+
use $crate::__macro_helpers::{u8, Option, stringify};
673660

674661
let sel = $crate::sel!($selector);
675662
const NAME: &[u8] = stringify!($selector).as_bytes();
676663
$crate::__msg_send_id_helper!(@get_assert_consts NAME);
677664
let result: Option<$crate::rc::Id<_, _>>;
678-
match <RS as $crate::__macro_helpers::MsgSendId<_, _>>::send_message_id($obj, sel, ()) {
679-
Err(s) => panic!("{}", s),
680-
Ok(r) => result = r,
681-
}
665+
result = <RS as $crate::__macro_helpers::MsgSendId<_, _>>::send_message_id($obj, sel, ());
682666
result
683667
});
684668
[$obj:expr, $($selector:ident : $argument:expr),+ $(,)?] => ({
685-
use $crate::__macro_helpers::{concat, u8, Err, Ok, Option, panic, stringify};
669+
use $crate::__macro_helpers::{concat, u8, Option, stringify};
686670

687671
let sel = $crate::sel!($($selector:)+);
688672
const NAME: &[u8] = concat!($(stringify!($selector), ':'),+).as_bytes();
689673
$crate::__msg_send_id_helper!(@get_assert_consts NAME);
690674
let result: Option<$crate::rc::Id<_, _>>;
691-
match <RS as $crate::__macro_helpers::MsgSendId<_, _>>::send_message_id($obj, sel, ($($argument,)+)) {
692-
Err(s) => panic!("{}", s),
693-
Ok(r) => result = r,
694-
}
675+
result = <RS as $crate::__macro_helpers::MsgSendId<_, _>>::send_message_id($obj, sel, ($($argument,)+));
695676
result
696677
});
697678
}

objc2/src/message/apple/mod.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use super::{conditional_try, Encode, MessageArguments, MessageError};
1+
use super::conditional_try;
22
use crate::ffi;
33
use crate::runtime::{Class, Imp, Object, Sel};
4+
use crate::{Encode, MessageArguments};
45

56
#[cfg(target_arch = "x86")]
67
#[path = "x86.rs"]
@@ -24,11 +25,8 @@ unsafe trait MsgSendFn: Encode {
2425
}
2526

2627
#[inline]
27-
pub(crate) unsafe fn send_unverified<A, R>(
28-
receiver: *mut Object,
29-
sel: Sel,
30-
args: A,
31-
) -> Result<R, MessageError>
28+
#[track_caller]
29+
pub(crate) unsafe fn send_unverified<A, R>(receiver: *mut Object, sel: Sel, args: A) -> R
3230
where
3331
A: MessageArguments,
3432
R: Encode,
@@ -38,12 +36,13 @@ where
3836
}
3937

4038
#[inline]
39+
#[track_caller]
4140
pub(crate) unsafe fn send_super_unverified<A, R>(
4241
receiver: *mut Object,
4342
superclass: &Class,
4443
sel: Sel,
4544
args: A,
46-
) -> Result<R, MessageError>
45+
) -> R
4746
where
4847
A: MessageArguments,
4948
R: Encode,

objc2/src/message/gnustep.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
use core::mem;
22

3-
use super::{conditional_try, Encode, MessageArguments, MessageError};
3+
use super::conditional_try;
44
use crate::ffi;
55
use crate::runtime::{Class, Object, Sel};
6+
use crate::{Encode, MessageArguments};
67

7-
pub(crate) unsafe fn send_unverified<A, R>(
8-
receiver: *mut Object,
9-
sel: Sel,
10-
args: A,
11-
) -> Result<R, MessageError>
8+
#[track_caller]
9+
pub(crate) unsafe fn send_unverified<A, R>(receiver: *mut Object, sel: Sel, args: A) -> R
1210
where
1311
A: MessageArguments,
1412
R: Encode,
@@ -28,12 +26,13 @@ where
2826
unsafe { conditional_try(|| A::__invoke(msg_send_fn, receiver, sel, args)) }
2927
}
3028

29+
#[track_caller]
3130
pub(crate) unsafe fn send_super_unverified<A, R>(
3231
receiver: *mut Object,
3332
superclass: &Class,
3433
sel: Sel,
3534
args: A,
36-
) -> Result<R, MessageError>
35+
) -> R
3736
where
3837
A: MessageArguments,
3938
R: Encode,

0 commit comments

Comments
 (0)