fix(wireplumber): guard async load callbacks against use-after-free on teardown
The WirePlumber module registers three async callbacks (onDefaultNodesApiLoaded, onMixerApiLoaded, onPluginActivated) that receive a raw self pointer with a NULL GCancellable. WirePlumber cannot withdraw an in-flight callback, so if the module is destroyed before a queued callback fires (e.g. a temporary output/bar is removed while a component load is still pending, or during an audio route transition), the callback dereferences the freed self, causing heap corruption / a crash. Guard each of these callbacks with isModuleAlive(), which checks the existing static modules registry. The destructor already removes this from the registry before any teardown, so a missing entry means self is dangling and the callback bails out without touching it. A GCancellable cannot fix this cleanly here: every callback dereferences self on its first line, and wp_core_load_component completes via a WpTransition (not a GTask), so the cancellable is not recoverable from the GAsyncResult either. The liveness check must not touch self at all. Fixes #3974.
This commit is contained in:
@@ -36,6 +36,9 @@ class Wireplumber : public ALabel {
|
||||
std::vector<std::string> getWPIcon();
|
||||
|
||||
static std::list<waybar::modules::Wireplumber*> modules;
|
||||
// Returns true while `self` is still a live module. Async load/activation callbacks use this to
|
||||
// avoid dereferencing a `self` that was destroyed before the callback fired (see #3974).
|
||||
static bool isModuleAlive(waybar::modules::Wireplumber* self);
|
||||
|
||||
uint32_t resolvePhysicalSink(uint32_t start_id);
|
||||
uint32_t findPlaybackNodeId(const gchar* description);
|
||||
|
||||
Reference in New Issue
Block a user