Skip to content

Commit 1ce5971

Browse files
sentry[bot]Copilot
andauthored
Fix: Multitouch data handling memory safety (#117)
* Fix: Multitouch data handling memory safety * Update MiddleDrag/Managers/MultitouchManager.swift Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Karan Mohindroo <96403086+NullPointerDepressiveDisorder@users.noreply.github.com> --------- Signed-off-by: Karan Mohindroo <96403086+NullPointerDepressiveDisorder@users.noreply.github.com> Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 37b09b2 commit 1ce5971

1 file changed

Lines changed: 14 additions & 12 deletions

File tree

MiddleDrag/Managers/MultitouchManager.swift

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -855,25 +855,27 @@ extension MultitouchManager: DeviceMonitorDelegate {
855855
let modifierFlags = CGEventSource.flagsState(.hidSystemState)
856856

857857
// The touches pointer is only valid for the duration of this callback.
858-
// Copy touch data via raw memcpy — much cheaper than Swift Array allocation
859-
// + map closure that was causing per-frame GC pressure and jitter at 100Hz+.
858+
// Copy touch data into a Data value — Swift manages its lifetime automatically,
859+
// eliminating the use-after-free / double-free risk of manual raw pointer
860+
// allocation that can occur when rapid sleep/wake cycles cause concurrent
861+
// restart() calls while async closures are still queued on gestureQueue.
860862
let touchCount = Int(count)
861-
nonisolated(unsafe) let touchesPtr: UnsafeMutableRawPointer?
863+
let touchData: Data?
862864
if touchCount > 0 {
863865
let byteCount = touchCount * MemoryLayout<MTTouch>.stride
864-
let buffer = UnsafeMutableRawPointer.allocate(
865-
byteCount: byteCount, alignment: MemoryLayout<MTTouch>.alignment)
866-
unsafe buffer.copyMemory(from: touches, byteCount: byteCount)
867-
unsafe touchesPtr = unsafe buffer
866+
touchData = unsafe Data(bytes: touches, count: byteCount)
868867
} else {
869-
unsafe touchesPtr = nil
868+
touchData = nil
870869
}
871870

872871
gestureQueue.async { [weak self] in
873-
if let buffer = unsafe touchesPtr {
874-
defer { unsafe buffer.deallocate() }
875-
unsafe self?.gestureRecognizer.processTouches(
876-
buffer, count: touchCount, timestamp: timestamp, modifierFlags: modifierFlags)
872+
if let data = touchData {
873+
data.withUnsafeBytes { rawBuffer in
874+
guard let baseAddress = rawBuffer.baseAddress else { return }
875+
let buffer = UnsafeMutableRawPointer(mutating: baseAddress)
876+
unsafe self?.gestureRecognizer.processTouches(
877+
buffer, count: touchCount, timestamp: timestamp, modifierFlags: modifierFlags)
878+
}
877879
} else {
878880
// Zero touches — still notify so gesture recognizer can end via stableFrameCount
879881
unsafe self?.gestureRecognizer.processTouches(

0 commit comments

Comments
 (0)