Skip to content

Commit f0b65c2

Browse files
committed
Fix unsoundness in CGEventTap API
1 parent d4ce710 commit f0b65c2

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

core-graphics/src/event.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::event_source::CGEventSource;
33
use crate::geometry::CGPoint;
44
use core_foundation::{
55
base::{CFRelease, CFRetain, CFTypeID, TCFType},
6-
mach_port::{CFMachPort, CFMachPortRef},
6+
mach_port::{CFMachPort, CFMachPortInvalidate, CFMachPortRef},
77
};
88
use foreign_types::ForeignType;
99
use libc::c_void;
@@ -414,7 +414,7 @@ macro_rules! CGEventMaskBit {
414414
}
415415

416416
pub type CGEventTapProxy = *const c_void;
417-
pub type CGEventTapCallBackFn<'tap_life> =
417+
type CGEventTapCallBackFn<'tap_life> =
418418
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>;
419419
type CGEventTapCallBackInternal = unsafe extern "C" fn(
420420
proxy: CGEventTapProxy,
@@ -440,7 +440,6 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
440440
}
441441

442442
/// ```no_run
443-
///extern crate core_foundation;
444443
///use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
445444
///use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
446445
///let current = CFRunLoop::get_current();
@@ -456,9 +455,9 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
456455
/// ) {
457456
/// Ok(tap) => unsafe {
458457
/// let loop_source = tap
459-
/// .mach_port
458+
/// .mach_port()
460459
/// .create_runloop_source(0)
461-
/// .expect("Somethings is bad ");
460+
/// .expect("Runloop source creation failed");
462461
/// current.add_source(&loop_source, kCFRunLoopCommonModes);
463462
/// tap.enable();
464463
/// CFRunLoop::run_current();
@@ -467,9 +466,8 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
467466
/// }
468467
/// ```
469468
pub struct CGEventTap<'tap_life> {
470-
pub mach_port: CFMachPort,
471-
pub callback_ref:
472-
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>,
469+
mach_port: CFMachPort,
470+
_callback: Box<CGEventTapCallBackFn<'tap_life>>,
473471
}
474472

475473
impl<'tap_life> CGEventTap<'tap_life> {
@@ -485,7 +483,7 @@ impl<'tap_life> CGEventTap<'tap_life> {
485483
.fold(CGEventType::Null as CGEventMask, |mask, &etype| {
486484
mask | CGEventMaskBit!(etype)
487485
});
488-
let cb = Box::new(Box::new(callback) as CGEventTapCallBackFn);
486+
let cb: Box<CGEventTapCallBackFn> = Box::new(Box::new(callback));
489487
let cbr = Box::into_raw(cb);
490488
unsafe {
491489
let event_tap_ref = CGEventTapCreate(
@@ -500,7 +498,7 @@ impl<'tap_life> CGEventTap<'tap_life> {
500498
if !event_tap_ref.is_null() {
501499
Ok(Self {
502500
mach_port: (CFMachPort::wrap_under_create_rule(event_tap_ref)),
503-
callback_ref: Box::from_raw(cbr),
501+
_callback: Box::from_raw(cbr),
504502
})
505503
} else {
506504
let _ = Box::from_raw(cbr);
@@ -509,11 +507,21 @@ impl<'tap_life> CGEventTap<'tap_life> {
509507
}
510508
}
511509

510+
pub fn mach_port(&self) -> &CFMachPort {
511+
&self.mach_port
512+
}
513+
512514
pub fn enable(&self) {
513515
unsafe { CGEventTapEnable(self.mach_port.as_concrete_TypeRef(), true) }
514516
}
515517
}
516518

519+
impl Drop for CGEventTap<'_> {
520+
fn drop(&mut self) {
521+
unsafe { CFMachPortInvalidate(self.mach_port.as_CFTypeRef() as *mut _) };
522+
}
523+
}
524+
517525
foreign_type! {
518526
#[doc(hidden)]
519527
pub unsafe type CGEvent {

0 commit comments

Comments
 (0)