Skip to content

Commit 9f761ff

Browse files
committed
Document why we do NULL receiver checks on GNUStep
Initially introduced in f4f95a4, but the documentation behind it was sparse
1 parent 1a22ac1 commit 9f761ff

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

crates/objc2/src/runtime/message_receiver.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,15 @@ mod msg_send_primitive {
154154
args: A,
155155
) -> R {
156156
let msg_send_fn = R::MSG_SEND;
157+
// Note: Modern Objective-C compilers have a workaround to ensure that
158+
// messages to `nil` with a struct return produces `mem::zeroed()`,
159+
// see:
160+
// <https://www.sealiesoftware.com/blog/archive/2012/2/29/objc_explain_return_value_of_message_to_nil.html>
161+
//
162+
// We _could_ technically do something similar, but since we're
163+
// disallowing messages to `nil` with `debug_assertions` enabled
164+
// anyhow, and since Rust has a much stronger type-system that
165+
// disallows NULL/nil in most cases, we won't bother supporting it.
157166
unsafe { A::__invoke(msg_send_fn, receiver, sel, args) }
158167
}
159168

@@ -206,13 +215,21 @@ mod msg_send_primitive {
206215
sel: Sel,
207216
args: A,
208217
) -> R {
209-
// If `receiver` is NULL, objc_msg_lookup will return a standard C-method
210-
// taking two arguments, the receiver and the selector. Transmuting and
211-
// calling such a function with multiple parameters is UB, so instead we
212-
// return NULL directly.
218+
// If `receiver` is NULL, objc_msg_lookup will return a standard
219+
// C-method taking two arguments, the receiver and the selector.
220+
//
221+
// Transmuting and calling such a function with multiple parameters is
222+
// safe as long as the return value is a primitive (and e.g. not a big
223+
// struct or array).
224+
//
225+
// However, when the return value is a floating point value, the float
226+
// will end up as some undefined value, usually NaN, which is
227+
// incompatible with Apple's platforms. As such, we insert this extra
228+
// NULL check here.
213229
if receiver.is_null() {
214230
// SAFETY: Caller guarantees that messages to NULL-receivers only
215-
// return pointers, and a mem::zeroed pointer is just a NULL-pointer.
231+
// return pointers or primitive values, and a mem::zeroed pointer
232+
// / primitive is just a NULL-pointer or a zeroed primitive.
216233
return unsafe { mem::zeroed() };
217234
}
218235

0 commit comments

Comments
 (0)