Skip to content

Commit 36fba6a

Browse files
committed
Fix unsoundness in CGEventTap API
1 parent b2fdaf4 commit 36fba6a

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

core-graphics/src/event.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use bitflags::bitflags;
66
use core::ffi::{c_ulong, c_void};
77
use core_foundation::{
88
base::{CFRelease, CFRetain, CFTypeID, TCFType},
9-
mach_port::{CFMachPort, CFMachPortRef},
9+
mach_port::{CFMachPort, CFMachPortInvalidate, CFMachPortRef},
1010
};
1111
use foreign_types::{foreign_type, ForeignType};
1212
use std::mem::ManuallyDrop;
@@ -417,7 +417,7 @@ macro_rules! CGEventMaskBit {
417417
}
418418

419419
pub type CGEventTapProxy = *const c_void;
420-
pub type CGEventTapCallBackFn<'tap_life> =
420+
type CGEventTapCallBackFn<'tap_life> =
421421
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>;
422422
type CGEventTapCallBackInternal = unsafe extern "C" fn(
423423
proxy: CGEventTapProxy,
@@ -458,9 +458,9 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
458458
/// ) {
459459
/// Ok(tap) => unsafe {
460460
/// let loop_source = tap
461-
/// .mach_port
461+
/// .mach_port()
462462
/// .create_runloop_source(0)
463-
/// .expect("Somethings is bad ");
463+
/// .expect("Runloop source creation failed");
464464
/// current.add_source(&loop_source, kCFRunLoopCommonModes);
465465
/// tap.enable();
466466
/// CFRunLoop::run_current();
@@ -469,9 +469,8 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
469469
/// }
470470
/// ```
471471
pub struct CGEventTap<'tap_life> {
472-
pub mach_port: CFMachPort,
473-
pub callback_ref:
474-
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>,
472+
mach_port: CFMachPort,
473+
_callback: Box<CGEventTapCallBackFn<'tap_life>>,
475474
}
476475

477476
impl<'tap_life> CGEventTap<'tap_life> {
@@ -487,7 +486,7 @@ impl<'tap_life> CGEventTap<'tap_life> {
487486
.fold(CGEventType::Null as CGEventMask, |mask, &etype| {
488487
mask | CGEventMaskBit!(etype)
489488
});
490-
let cb = Box::new(Box::new(callback) as CGEventTapCallBackFn);
489+
let cb: Box<CGEventTapCallBackFn> = Box::new(Box::new(callback));
491490
let cbr = Box::into_raw(cb);
492491
unsafe {
493492
let event_tap_ref = CGEventTapCreate(
@@ -502,7 +501,7 @@ impl<'tap_life> CGEventTap<'tap_life> {
502501
if !event_tap_ref.is_null() {
503502
Ok(Self {
504503
mach_port: (CFMachPort::wrap_under_create_rule(event_tap_ref)),
505-
callback_ref: Box::from_raw(cbr),
504+
_callback: Box::from_raw(cbr),
506505
})
507506
} else {
508507
let _ = Box::from_raw(cbr);
@@ -511,11 +510,21 @@ impl<'tap_life> CGEventTap<'tap_life> {
511510
}
512511
}
513512

513+
pub fn mach_port(&self) -> &CFMachPort {
514+
&self.mach_port
515+
}
516+
514517
pub fn enable(&self) {
515518
unsafe { CGEventTapEnable(self.mach_port.as_concrete_TypeRef(), true) }
516519
}
517520
}
518521

522+
impl Drop for CGEventTap<'_> {
523+
fn drop(&mut self) {
524+
unsafe { CFMachPortInvalidate(self.mach_port.as_CFTypeRef() as *mut _) };
525+
}
526+
}
527+
519528
foreign_type! {
520529
#[doc(hidden)]
521530
pub unsafe type CGEvent {

0 commit comments

Comments
 (0)