Skip to content

Fix remaining mpv thread safety gaps causing SIGSEGV#138

Merged
willfish merged 3 commits intomasterfrom
fix/mpv-remaining-thread-safety
Mar 9, 2026
Merged

Fix remaining mpv thread safety gaps causing SIGSEGV#138
willfish merged 3 commits intomasterfrom
fix/mpv-remaining-thread-safety

Conversation

@willfish
Copy link
Copy Markdown
Owner

@willfish willfish commented Mar 9, 2026

Summary

mpv engine (commit 1)

  • Wrap two unprotected e.handle.GetProperty("playlist-pos", ...) calls in the event handler (EndFileError and EndFileEOF/EndFileStop branches) with the engine mutex, closing a race against concurrent callers from the ticker, D-Bus, and frontend goroutines
  • Engine.Close() now holds the mutex through TerminateDestroy() so no concurrent caller can access the handle mid-destroy
  • All public Engine methods check a closed flag and bail out early after Close() has run
  • ServiceShutdown waits for the ticker goroutine to fully exit (via tickerDone channel) before calling engine.Close()

Scrobble state, MPRIS, notifier (commit 2)

  • Add scrobbleMu protecting scrobbleTrackID, scrobbleElapsed, and scrobbled fields - these were read/written from both the event callback goroutine and the ticker goroutine with no synchronisation
  • MPRIS: add closed flag checked by setProp, UpdatePosition, exportArtwork, SeekOffset, and SetPosition - prevents conn.Emit() racing with conn.Close() during shutdown
  • Notifier: add closed flag checked by Notify() - prevents D-Bus calls on a closed connection during shutdown

Follows up on #137 which added mutex protection to public Engine methods but missed these internal paths and adjacent components.

Test plan

  • go test -tags nocgo ./... passes
  • golangci-lint run --build-tags nocgo reports 0 issues
  • npm run check passes (no frontend changes, sanity check)
  • Manual: play music, skip tracks rapidly, switch radio stations, quit app cleanly - no SIGSEGV
  • Manual: verify scrobbles still submit correctly to Last.fm/ListenBrainz
  • Manual: verify media key controls (MPRIS) still work during playback

willfish added 3 commits March 9, 2026 07:43
The previous fix (#137) added mutex protection to all public Engine
methods but missed two GetProperty calls inside the event handler and
left a shutdown race where TerminateDestroy could run while other
goroutines were still using the mpv handle.

Event handler: wrap the two unprotected e.handle.GetProperty calls
at EndFileError and EndFileEOF/EndFileStop with the engine mutex so
they serialise against concurrent callers from the ticker, D-Bus,
and frontend goroutines.

Shutdown race: Engine.Close now holds the mutex through
TerminateDestroy so no concurrent caller can access the handle
mid-destroy. All public methods check a closed flag and bail out
early after Close has run. ServiceShutdown waits for the ticker
goroutine to fully exit before calling engine.Close.
Scrobble state: add scrobbleMu to protect scrobbleTrackID,
scrobbleElapsed, and scrobbled fields which are written from event
callbacks (startScrobbleTracking) and read/written from the ticker
goroutine (checkScrobble). Snapshot elapsed time before releasing
the lock so DB/network calls happen outside the critical section.

MPRIS: add closed flag checked by setProp, UpdatePosition,
exportArtwork, SeekOffset, and SetPosition. Close() sets the flag
under the mutex before closing the D-Bus connection, preventing
concurrent conn.Emit() calls from racing with conn.Close().
Protect m.artPath writes and snapshot m.artDir in exportArtwork.

Notifier: add closed flag checked by Notify(). Close() sets the
flag under the mutex before closing the D-Bus connection, preventing
concurrent Notify() calls from operating on a closed connection.
Go 1.25.7 has two stdlib vulnerabilities (GO-2026-4602 in os,
GO-2026-4601 in net/url) that cause the Security CI job to fail.
Both are fixed in 1.25.8.
@willfish willfish merged commit 74dc843 into master Mar 9, 2026
5 checks passed
@willfish willfish deleted the fix/mpv-remaining-thread-safety branch March 9, 2026 08:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant