Skip to content

[v3 / linux] Concurrent map read/write fatal in linuxSystemTray when menu is updated #5335

@Sipaha

Description

@Sipaha

Description

A v3 app on Linux that updates its system-tray menu at runtime crashes with fatal error: concurrent map read and map write. The runtime aborts inside the godbus callback linuxSystemTray.GetLayout (or GetGroupProperties) on the godbus worker goroutine, and the process is forcibly killed — recover() cannot intercept it.

linuxSystemTray.itemMap and the per-item dbusItem.V1 property maps are written from the main thread (setMenu, update, the systrayMenuItem setters) while the dbusmenu callbacks run on the godbus worker goroutine. The pre-existing // FIXME: RLock? comments at v3/pkg/application/systemtray_linux.go:703,727 already flag the gap.

Reproduced on v3.0.0-alpha.78; the same code is still on master at the time of writing (latest tag v3.0.0-alpha.84).

To Reproduce

  1. Build any v3 app that has a SystemTray with a menu and calls SystemTray.SetMenu(...) periodically — e.g. on a 30-second tick, or in response to events (timer started/stopped, sync state changed, …).
  2. Run it on Linux with the panel/system-tray visible — every panel paint triggers GetLayout / GetGroupProperties on the dbusmenu interface.
  3. Wait. A few SetMenu calls per minute is enough; under heavier load it fires within seconds.

A pure-Go reproducer that triggers the same fatal under go test -race without needing a session bus will be included in the accompanying PR (TestLinuxSystemTrayConcurrentSetMenu in v3/pkg/application/systemtray_linux_race_test.go). Removing the locks on a clean master reproduces the crash in milliseconds with the exact same stack frames as the production trace below.

Expected behaviour

SystemTray.SetMenu must be safe to call concurrently with the dbusmenu callbacks dispatched by godbus. Today it is not, and the resulting fatal is unrecoverable.

Screenshots

No response

Attempted Fixes

A patch with sync.RWMutex on linuxSystemTray plus a -race regression test is ready.

System Details

Wails:    v3.0.0-alpha.78 (also reproduces on current master / v3.0.0-alpha.84)
OS:       Ubuntu 25.x
Kernel:   Linux 6.17.0-20-generic
DE:       GNOME on Wayland (also reproduces on X11)
Go:       go1.26.1 linux/amd64

Additional context

Stack trace from a real production crash:

fatal error: concurrent map read and map write

goroutine 3450 [running]:
internal/runtime/maps.fatal(...)
	runtime/panic.go:1181 +0x18
github.com/wailsapp/wails/v3/pkg/application.(*linuxSystemTray).GetLayout(0x1306ff82e8c0, ...)
	github.com/wailsapp/wails/v3@v3.0.0-alpha.78/pkg/application/systemtray_linux.go:728 +0x3f
reflect.Value.call(...)
	reflect/value.go:586 +0xf06
github.com/godbus/dbus/v5.exportedMethod.Call(...)
	github.com/godbus/dbus/v5@v5.2.2/default_handler.go:128 +0x247
github.com/godbus/dbus/v5.(*Conn).handleCall(...)
	github.com/godbus/dbus/v5@v5.2.2/export.go:193 +0x545
created by github.com/godbus/dbus/v5.(*Conn).inWorker in goroutine 35
	github.com/godbus/dbus/v5@v5.2.2/conn.go:435 +0x233

GetGroupProperties on the same goroutine type (godbus inWorker) crashes the same way — the test in the linked PR exercises both paths.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't workingLinuxv3

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions