From 445e2aec1ff3f289a268711a41522d72e0ee7734 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 5 Jul 2026 22:02:49 +0200 Subject: [PATCH] fix(bar): avoid use-after-free segfault on exit Members are destroyed in reverse declaration order, so modules_all_ (and the modules it owns) are gone before the GtkWindow. Tearing down a mapped window emits `unmap`, whose handler runs toggleSuspend() over the already freed modules. Disconnect the map/unmap handlers in ~Bar first. Fixes #5182 --- include/bar.hpp | 4 ++++ src/bar.cpp | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/bar.hpp b/include/bar.hpp index f3dfa781..2dc51379 100644 --- a/include/bar.hpp +++ b/include/bar.hpp @@ -131,6 +131,10 @@ class Bar : public sigc::trackable { waybar::util::KillSignalAction onSigusr1 = util::SIGNALACTION_DEFAULT_SIGUSR1; waybar::util::KillSignalAction onSigusr2 = util::SIGNALACTION_DEFAULT_SIGUSR2; + + /* Disconnected in ~Bar before the modules are destroyed (#5182). */ + sigc::connection map_conn_; + sigc::connection unmap_conn_; }; } // namespace waybar diff --git a/src/bar.cpp b/src/bar.cpp index 1eb5ce41..ec3189c6 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -269,12 +269,12 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap)); - window.signal_unmap().connect([this]() { + unmap_conn_ = window.signal_unmap().connect([this]() { spdlog::debug("Output {} unmapped (DPMS off), suspending modules", output->name); toggleSuspend(true); }); - window.signal_map().connect([this]() { + map_conn_ = window.signal_map().connect([this]() { spdlog::debug("Output {} mapped (DPMS on), resuming modules", output->name); toggleSuspend(false); }); @@ -352,7 +352,12 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) } /* Need to define it here because of forward declared members */ -waybar::Bar::~Bar() = default; +waybar::Bar::~Bar() { + /* Destroying the window emits `unmap`, whose handler runs toggleSuspend() over + * modules_all_ -- already freed by this point. Disconnect first (#5182). */ + unmap_conn_.disconnect(); + map_conn_.disconnect(); +} void waybar::Bar::setMode(const std::string& mode) { using namespace std::literals::string_literals;