Skip to content

Commit 0dc236c

Browse files
committed
Push pointers in block typedefs up
This makes interacting with typedef'd blocks a lot safer, there basically shouldn't be a need for `RcBlock::as_ptr` any more.
1 parent 954f940 commit 0dc236c

9 files changed

Lines changed: 69 additions & 56 deletions

File tree

crates/dispatch2/src/data.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl DispatchData {
2121
#[inline]
2222
pub fn from_bytes(data: &[u8]) -> DispatchRetained<Self> {
2323
// TODO: Autogenerate?
24-
const DISPATCH_DATA_DESTRUCTOR_DEFAULT: crate::dispatch_block_t = ptr::null_mut();
24+
const DISPATCH_DATA_DESTRUCTOR_DEFAULT: Option<&crate::dispatch_block_t> = None;
2525

2626
let ptr = NonNull::new(data.as_ptr().cast_mut()).unwrap().cast();
2727

@@ -50,12 +50,10 @@ impl DispatchData {
5050
// We don't care which queue ends up running the destructor.
5151
let queue = None;
5252

53-
let destructor = (&*NOOP_BLOCK as *const block2::Block<_>).cast_mut();
54-
5553
// SAFETY: Buffer pointer is valid for the given number of bytes.
5654
// Queue handle is valid, and the destructor is a NULL value which
5755
// indicates the buffer should be copied.
58-
unsafe { Self::new(ptr, data.len(), queue, destructor) }
56+
unsafe { Self::new(ptr, data.len(), queue, Some(&NOOP_BLOCK)) }
5957
}
6058

6159
/// Creates a dispatch data object with ownership of the given contiguous
@@ -74,7 +72,6 @@ impl DispatchData {
7472
// dispatch_data_create().
7573
let _ = unsafe { alloc::boxed::Box::<[u8]>::from_raw(raw) };
7674
});
77-
let destructor = block2::RcBlock::as_ptr(&destructor);
7875

7976
// We don't care which queue ends up running the destructor.
8077
// Box<[u8]> is sendable, so it's fine for us to potentially pass it
@@ -84,7 +81,7 @@ impl DispatchData {
8481
// SAFETY: Buffer pointer is valid for the given number of bytes.
8582
//
8683
// The destructor is valid and correctly destroys the buffer.
87-
unsafe { Self::new(ptr, data_len, queue, destructor) }
84+
unsafe { Self::new(ptr, data_len, queue, Some(&destructor)) }
8885
}
8986

9087
/// Copy all the non-contiguous parts of the data into a contiguous
@@ -114,23 +111,24 @@ impl DispatchData {
114111
},
115112
);
116113

117-
let block = block2::RcBlock::as_ptr(&block);
118114
// SAFETY: Transmute from return type `u8` to `bool` is safe, since we
119115
// only ever return `1` / `true`.
120116
// TODO: Fix the need for this in `block2`.
121117
let block = unsafe {
122118
core::mem::transmute::<
123-
*mut block2::Block<
124-
dyn Fn(NonNull<DispatchData>, usize, NonNull<core::ffi::c_void>, usize) -> u8,
119+
&'_ block2::Block<
120+
dyn Fn(NonNull<DispatchData>, usize, NonNull<core::ffi::c_void>, usize) -> u8
121+
+ '_,
125122
>,
126-
*mut block2::Block<
127-
dyn Fn(NonNull<DispatchData>, usize, NonNull<core::ffi::c_void>, usize) -> bool,
123+
&'_ block2::Block<
124+
dyn Fn(NonNull<DispatchData>, usize, NonNull<core::ffi::c_void>, usize) -> bool
125+
+ '_,
128126
>,
129-
>(block)
127+
>(&block)
130128
};
131129

132130
// SAFETY: The block is implemented correctly.
133-
unsafe { self.apply(block) };
131+
self.apply(block);
134132
contents.take()
135133
}
136134
}
@@ -195,7 +193,7 @@ mod tests {
195193
NonNull::new(data.as_ptr().cast_mut()).unwrap().cast(),
196194
data.len(),
197195
None,
198-
RcBlock::as_ptr(&destructor),
196+
Some(&destructor),
199197
)
200198
};
201199

crates/dispatch2/translation-config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,9 @@ fn.dispatch_allow_send_signals.unsafe = true
275275
fn.dispatch_semaphore_create.unsafe = false
276276

277277
# The handler function must be correct.
278+
fn.dispatch_source_set_event_handler.unsafe = true
278279
fn.dispatch_source_set_event_handler_f.unsafe = true
280+
fn.dispatch_source_set_cancel_handler.unsafe = true
279281
fn.dispatch_source_set_cancel_handler_f.unsafe = true
282+
fn.dispatch_source_set_registration_handler.unsafe = true
280283
fn.dispatch_source_set_registration_handler_f.unsafe = true

crates/header-translator/src/rust_type.rs

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,30 +1431,19 @@ impl PointeeTy {
14311431
}
14321432

14331433
fn is_cf_type(&self) -> bool {
1434-
match self {
1435-
// Recurse into typedefs
1436-
Self::TypeDef { to, .. } => to.is_cf_type(),
1437-
Self::CFTypeDef { .. } => true,
1438-
_ => false,
1439-
}
1434+
matches!(self.through_typedef(), Self::CFTypeDef { .. })
14401435
}
14411436

14421437
fn is_dispatch_type(&self) -> bool {
1443-
match self {
1444-
// Recurse into typedefs
1445-
Self::TypeDef { to, .. } => to.is_dispatch_type(),
1446-
Self::DispatchTypeDef { .. } => true,
1447-
_ => false,
1448-
}
1438+
matches!(self.through_typedef(), Self::DispatchTypeDef { .. })
14491439
}
14501440

14511441
fn is_network_type(&self) -> bool {
1452-
match self {
1453-
// Recurse into typedefs
1454-
Self::TypeDef { to, .. } => to.is_network_type(),
1455-
Self::NetworkTypeDef { .. } => true,
1456-
_ => false,
1457-
}
1442+
matches!(self.through_typedef(), Self::NetworkTypeDef { .. })
1443+
}
1444+
1445+
fn is_block_type(&self) -> bool {
1446+
matches!(self.through_typedef(), Self::Block { .. })
14581447
}
14591448

14601449
fn is_subtype_of(&self, other: &Self) -> bool {
@@ -2476,10 +2465,7 @@ impl Ty {
24762465
**pointee = Self::Pointee(PointeeTy::TypeDef { id, to });
24772466
return inner;
24782467
} else {
2479-
error!(
2480-
?pointee,
2481-
"is_object_like/is_cf_type/is_os_type but not Pointee"
2482-
);
2468+
error!(?pointee, "is_object_like but not Pointee");
24832469
}
24842470
}
24852471
} else {
@@ -2947,6 +2933,7 @@ impl Ty {
29472933
|| self.is_cf_type()
29482934
|| self.is_dispatch_type()
29492935
|| self.is_network_type()
2936+
|| self.is_block_type()
29502937
}
29512938

29522939
/// Determine whether the inner type of a `Pointer` is object-like.
@@ -2985,6 +2972,15 @@ impl Ty {
29852972
}
29862973
}
29872974

2975+
/// Determine whether the inner type of a `Pointer` is a block.
2976+
fn is_block_type(&self) -> bool {
2977+
if let Self::Pointee(pointee_ty) = self.through_typedef() {
2978+
pointee_ty.is_block_type()
2979+
} else {
2980+
false
2981+
}
2982+
}
2983+
29882984
/// Determine whether the pointee inside a `Pointer` is the inner
29892985
/// struct/void type required for a type to be considered a CF type.
29902986
///
@@ -3257,13 +3253,23 @@ impl Ty {
32573253
write!(f, " -> Option<&'static {}>", pointee.behind_pointer(true))
32583254
}
32593255
}
3256+
Self::Pointer {
3257+
nullability: _,
3258+
lifetime: _, // TODO
3259+
bounds: PointerBounds::Single,
3260+
pointee,
3261+
..
3262+
} if pointee.is_block_type() => {
3263+
// TODO: Emit `RcBlock` or similar.
3264+
write!(f, " -> {}", self.plain(true))
3265+
}
32603266
Self::Pointer {
32613267
nullability,
32623268
lifetime: _, // TODO: Use this somehow?
32633269
bounds: PointerBounds::Single,
32643270
pointee,
32653271
..
3266-
} if pointee.is_object_like() && !pointee.is_static_object() => {
3272+
} if pointee.is_object_like() => {
32673273
// NOTE: We return CF types as `Retained` for now, since we
32683274
// don't have support for the CF wrapper in msg_send! yet.
32693275
if *nullability == Nullability::NonNull {
@@ -3324,7 +3330,7 @@ impl Ty {
33243330
bounds: PointerBounds::Single,
33253331
pointee,
33263332
..
3327-
} if pointee.is_object_like() => {
3333+
} if pointee.is_object_like() && !pointee.is_block_type() => {
33283334
// NULL -> error
33293335
Box::new(move |f| {
33303336
write!(
@@ -4038,18 +4044,22 @@ impl Ty {
40384044
*no_escape = arg_no_escape;
40394045
arg_no_escape = false;
40404046
}
4047+
// Ignore `arg_no_escape` on typedefs for now.
4048+
Self::Pointee(PointeeTy::TypeDef { .. }) => {
4049+
arg_no_escape = false;
4050+
}
40414051
_ => {}
40424052
},
4043-
// Ignore typedefs for now
4053+
// Ignore `arg_no_escape` on typedefs for now.
40444054
Self::TypeDef { .. } => {
4045-
arg_sendable = None;
40464055
arg_no_escape = false;
40474056
}
40484057
_ => {}
40494058
}
40504059

40514060
if arg_sendable.is_some() {
4052-
warn!(?ty, "did not consume sendable in argument");
4061+
// Important for soundness.
4062+
error!(?ty, "did not consume sendable in argument");
40534063
}
40544064

40554065
if arg_no_escape {
@@ -4347,7 +4357,8 @@ impl Ty {
43474357

43484358
pub(crate) fn is_retainable(&self) -> bool {
43494359
if let Self::Pointer { pointee, .. } = self {
4350-
pointee.is_object_like() && !pointee.is_static_object()
4360+
// Unsure if static items and blocks should be considered retainable?
4361+
pointee.is_object_like() && !pointee.is_static_object() && !pointee.is_block_type()
43514362
} else {
43524363
false
43534364
}
@@ -4386,7 +4397,7 @@ impl Ty {
43864397
Self::Struct { fields, .. } | Self::Union { fields, .. } => {
43874398
fields.iter().any(|(_, field)| field.needs_simd())
43884399
}
4389-
Self::Pointee(
4400+
Self::Pointee(pointee) => match pointee.through_typedef() {
43904401
PointeeTy::Fn {
43914402
result_type,
43924403
arguments,
@@ -4396,8 +4407,9 @@ impl Ty {
43964407
result_type,
43974408
arguments,
43984409
..
4399-
},
4400-
) => result_type.needs_simd() || arguments.iter().any(|arg| arg.needs_simd()),
4410+
} => result_type.needs_simd() || arguments.iter().any(|arg| arg.needs_simd()),
4411+
_ => false,
4412+
},
44014413
_ => false,
44024414
}
44034415
}

crates/objc2/src/topics/FRAMEWORKS_CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6868
* **BREAKING**: Use `Result<(), Retained<NSError>>` in more methods.
6969
* Fixed `SCContentSharingPickerConfiguration` having generics even though it shouldn't.
7070
* `NSArray`'s and `NSSet`'s `Debug` impl longer requires the `NSEnumerator` feature.
71+
* **BREAKING**: Type aliases now refer to the block instead of a pointer to the block.
72+
* **BREAKING**: Methods with blocks as type-aliases now take `&Block` instead of `*mut Block`.
7173

7274
## [0.3.2] - 2025-10-04
7375
[0.3.2]: https://github.com/madsmtm/objc2/compare/frameworks-0.3.1...frameworks-0.3.2

examples/metal/default_xcode_game/renderer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,9 @@ impl Renderer {
322322

323323
let block_sema = self.in_flight_semaphore().clone();
324324
unsafe {
325-
command_buffer.addCompletedHandler(RcBlock::as_ptr(&RcBlock::new(move |_buffer| {
325+
command_buffer.addCompletedHandler(&RcBlock::new(move |_buffer| {
326326
block_sema.signal();
327-
})))
327+
}))
328328
};
329329

330330
self.update_dynamic_buffer_state();

examples/metal/events/main.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,7 @@ fn main() {
4444
},
4545
);
4646

47-
unsafe {
48-
shared_event.notifyListener_atValue_block(
49-
&shared_event_listener,
50-
2,
51-
RcBlock::as_ptr(&notify_block),
52-
)
53-
};
47+
unsafe { shared_event.notifyListener_atValue_block(&shared_event_listener, 2, &notify_block) };
5448

5549
// Encode GPU work
5650
command_buffer.encodeSignalEvent_value(shared_event.as_ref(), 1);

examples/metal/raytracing/renderer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ impl Renderer {
433433
let block = block2::RcBlock::new(move |_| {
434434
sem.release();
435435
});
436-
unsafe { command_buffer.addCompletedHandler(block2::RcBlock::as_ptr(&block)) };
436+
unsafe { command_buffer.addCompletedHandler(&block) };
437437
let width = self.size.get().width as NSUInteger;
438438
let height = self.size.get().height as NSUInteger;
439439
let threads_per_thread_group = MTLSize {

framework-crates/objc2-av-foundation/translation-config.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,7 @@ class.AVPlayerInterstitialEvent.categories.MutableEvents.skipped = true
6969

7070
# Breaks type-safety, you must check encodings before accessing a value.
7171
class.NSValue.unsafe = true
72+
73+
# Must be unsafe, non-block parameters have `NS_SWIFT_SENDABLE` which we don't
74+
# know how to handle.
75+
class.AVContentKeySession.methods."processContentKeyRequestWithIdentifier:initializationData:options:".unsafe = true

generated

Submodule generated updated 236 files

0 commit comments

Comments
 (0)