mac/common: fix usage of vo struct after vo uninit race

we keep track of the current vo struct to flag for events that are
initiated async by various thread from different system notifications.
the problem here is the usage of that vo struct after uninit.

make accessing of that vo struct atomic and clear it on uninit, so it
can't be used afterwards by concurrent threads from system
notifications or events.

Fixes #15088
This commit is contained in:
der richter 2024-10-14 21:47:37 +02:00
parent 3172186226
commit ff64d87bb4
3 changed files with 16 additions and 18 deletions

View File

@ -40,7 +40,7 @@ class CocoaCB: Common, EventSubscriber {
} }
func preinit(_ vo: UnsafeMutablePointer<vo>) { func preinit(_ vo: UnsafeMutablePointer<vo>) {
self.vo = vo eventsLock.withLock { self.vo = vo }
input = InputHelper(vo.pointee.input_ctx, option) input = InputHelper(vo.pointee.input_ctx, option)
if backendState == .uninitialized { if backendState == .uninitialized {
@ -57,12 +57,13 @@ class CocoaCB: Common, EventSubscriber {
} }
func uninit() { func uninit() {
eventsLock.withLock { self.vo = nil }
window?.orderOut(nil) window?.orderOut(nil)
window?.close() window?.close()
} }
func reconfig(_ vo: UnsafeMutablePointer<vo>) { func reconfig(_ vo: UnsafeMutablePointer<vo>) {
self.vo = vo eventsLock.withLock { self.vo = vo }
if backendState == .needsInit { if backendState == .needsInit {
DispatchQueue.main.sync { self.initBackend(vo) } DispatchQueue.main.sync { self.initBackend(vo) }
} else if option.vo.auto_window_resize { } else if option.vo.auto_window_resize {

View File

@ -22,7 +22,6 @@ class Common: NSObject {
var option: OptionHelper var option: OptionHelper
var input: InputHelper? var input: InputHelper?
var log: LogHelper var log: LogHelper
var vo: UnsafeMutablePointer<vo>?
let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue") let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue")
@objc var window: Window? @objc var window: Window?
@ -32,6 +31,7 @@ class Common: NSObject {
var link: CVDisplayLink? var link: CVDisplayLink?
let eventsLock = NSLock() let eventsLock = NSLock()
var vo: UnsafeMutablePointer<vo>?
var events: Int = 0 var events: Int = 0
var lightSensor: io_connect_t = 0 var lightSensor: io_connect_t = 0
@ -145,6 +145,7 @@ class Common: NSObject {
} }
func uninitCommon() { func uninitCommon() {
eventsLock.withLock { self.vo = nil }
setCursorVisibility(true) setCursorVisibility(true)
stopDisplaylink() stopDisplaylink()
uninitLightSensor() uninitLightSensor()
@ -455,24 +456,20 @@ class Common: NSObject {
} }
func flagEvents(_ ev: Int) { func flagEvents(_ ev: Int) {
eventsLock.lock() eventsLock.withLock {
events |= ev events |= ev
eventsLock.unlock() guard let vo = vo else { return }
guard let vo = vo else {
log.warning("vo nil in flagEvents")
return
}
vo_wakeup(vo) vo_wakeup(vo)
} }
}
func checkEvents() -> Int { func checkEvents() -> Int {
eventsLock.lock() eventsLock.withLock {
let ev = events let ev = events
events = 0 events = 0
eventsLock.unlock()
return ev return ev
} }
}
func windowDidEndAnimation() {} func windowDidEndAnimation() {}
func windowSetToFullScreen() {} func windowSetToFullScreen() {}

View File

@ -29,7 +29,7 @@ class MacCommon: Common {
let log = LogHelper(mp_log_new(vo, vo.pointee.log, "mac")) let log = LogHelper(mp_log_new(vo, vo.pointee.log, "mac"))
let option = OptionHelper(vo, vo.pointee.global) let option = OptionHelper(vo, vo.pointee.global)
super.init(option, log) super.init(option, log)
self.vo = vo eventsLock.withLock { self.vo = vo }
input = InputHelper(vo.pointee.input_ctx, option) input = InputHelper(vo.pointee.input_ctx, option)
presentation = Presentation(common: self) presentation = Presentation(common: self)
timer = PreciseTimer(common: self) timer = PreciseTimer(common: self)
@ -41,7 +41,7 @@ class MacCommon: Common {
} }
@objc func config(_ vo: UnsafeMutablePointer<vo>) -> Bool { @objc func config(_ vo: UnsafeMutablePointer<vo>) -> Bool {
self.vo = vo eventsLock.withLock { self.vo = vo }
DispatchQueue.main.sync { DispatchQueue.main.sync {
let previousActiveApp = getActiveApp() let previousActiveApp = getActiveApp()