@@ -10,6 +10,17 @@ bool isValidNodeId(uint32_t id) { return id > 0 && id < G_MAXUINT32; }
1010
1111std::list<waybar::modules::Wireplumber*> waybar::modules::Wireplumber::modules;
1212
13+ // Async load/activation callbacks (onDefaultNodesApiLoaded, onMixerApiLoaded, onPluginActivated)
14+ // are handed a raw `self` pointer with no GCancellable, and WirePlumber has no way to withdraw an
15+ // in-flight callback. If the module is destroyed before such a callback fires (e.g. an output/bar
16+ // is removed while a component load is still pending, or during an audio route transition), the
17+ // callback would dereference a freed `self`. The destructor removes `this` from this registry
18+ // before any teardown, so a missing entry means `self` is dangling and the callback must bail out
19+ // without touching it. See https://github.com/Alexays/Waybar/issues/3974.
20+ bool waybar::modules::Wireplumber::isModuleAlive (waybar::modules::Wireplumber* self) {
21+ return std::find (modules.begin (), modules.end (), self) != modules.end ();
22+ }
23+
1324waybar::modules::Wireplumber::Wireplumber (const std::string& id, const Json::Value& config)
1425 : ALabel(config, " wireplumber" , id, " {volume}%" ),
1526 wp_core_(nullptr ),
@@ -387,6 +398,10 @@ void waybar::modules::Wireplumber::onObjectManagerInstalled(waybar::modules::Wir
387398
388399void waybar::modules::Wireplumber::onPluginActivated (WpObject* p, GAsyncResult* res,
389400 waybar::modules::Wireplumber* self) {
401+ if (!isModuleAlive (self)) {
402+ return ;
403+ }
404+
390405 const auto * pluginName = wp_plugin_get_name (WP_PLUGIN (p));
391406 spdlog::debug (" [{}]: onPluginActivated: {}" , self->name_ , pluginName);
392407 g_autoptr (GError) error = nullptr ;
@@ -432,6 +447,10 @@ void waybar::modules::Wireplumber::prepare(waybar::modules::Wireplumber* self) {
432447
433448void waybar::modules::Wireplumber::onDefaultNodesApiLoaded (WpObject* p, GAsyncResult* res,
434449 waybar::modules::Wireplumber* self) {
450+ if (!isModuleAlive (self)) {
451+ return ;
452+ }
453+
435454 gboolean success = FALSE ;
436455 g_autoptr (GError) error = nullptr ;
437456
@@ -453,6 +472,10 @@ void waybar::modules::Wireplumber::onDefaultNodesApiLoaded(WpObject* p, GAsyncRe
453472
454473void waybar::modules::Wireplumber::onMixerApiLoaded (WpObject* p, GAsyncResult* res,
455474 waybar::modules::Wireplumber* self) {
475+ if (!isModuleAlive (self)) {
476+ return ;
477+ }
478+
456479 gboolean success = FALSE ;
457480 g_autoptr (GError) error = nullptr ;
458481
0 commit comments