From 2ac7c81958e87d2af8495e19c5f29832e1a215a1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 5 May 2026 14:44:39 +0200 Subject: [PATCH] pipewire: handle allocation failures And make sure we don't leak things in the error paths. --- src/pipewire/data-loop.c | 32 ++++++++++++++++++++------------ src/pipewire/impl-module.c | 12 +++++++++--- src/pipewire/stream.c | 10 +++++++--- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/pipewire/data-loop.c b/src/pipewire/data-loop.c index 73f4251bc..ea1a6b2c3 100644 --- a/src/pipewire/data-loop.c +++ b/src/pipewire/data-loop.c @@ -85,6 +85,19 @@ static int do_stop(struct spa_loop *loop, bool async, uint32_t seq, return 0; } +static void data_loop_free(struct pw_data_loop *loop) +{ + if (loop->loop && loop->created) + pw_loop_destroy(loop->loop); + + spa_hook_list_clean(&loop->listener_list); + + free(loop->affinity); + free(loop->class); + pw_free_strv(loop->classes); + free(loop); +} + static struct pw_data_loop *loop_new(struct pw_loop *loop, const struct spa_dict *props) { struct pw_data_loop *this; @@ -98,6 +111,7 @@ static struct pw_data_loop *loop_new(struct pw_loop *loop, const struct spa_dict } pw_log_debug("%p: new", this); + spa_hook_list_init(&this->listener_list); if (loop == NULL) { loop = pw_loop_new(props); @@ -142,14 +156,17 @@ static struct pw_data_loop *loop_new(struct pw_loop *loop, const struct spa_dict goto error_free; } this->classes = pw_strv_parse(class, strlen(class), INT_MAX, NULL); + if (this->classes == NULL) { + res = -ENOMEM; + goto error_free; + } if (!this->loop->name[0]) pw_loop_set_name(this->loop, name); - spa_hook_list_init(&this->listener_list); return this; error_free: - free(this); + data_loop_free(this); error_cleanup: errno = -res; return NULL; @@ -165,7 +182,6 @@ struct pw_data_loop *pw_data_loop_new(const struct spa_dict *props) return loop_new(NULL, props); } - /** Destroy a data loop * \param loop the data loop to destroy */ @@ -178,15 +194,7 @@ void pw_data_loop_destroy(struct pw_data_loop *loop) pw_data_loop_stop(loop); - if (loop->created) - pw_loop_destroy(loop->loop); - - spa_hook_list_clean(&loop->listener_list); - - free(loop->affinity); - free(loop->class); - pw_free_strv(loop->classes); - free(loop); + data_loop_free(loop); } SPA_EXPORT diff --git a/src/pipewire/impl-module.c b/src/pipewire/impl-module.c index f754dd9b5..765256b13 100644 --- a/src/pipewire/impl-module.c +++ b/src/pipewire/impl-module.c @@ -216,12 +216,15 @@ pw_context_load_module(struct pw_context *context, pw_properties_set(this->properties, PW_KEY_MODULE_NAME, name); + spa_list_prepend(&context->module_list, &this->link); + this->info.name = name ? strdup(name) : NULL; - this->info.filename = filename; - filename = NULL; + this->info.filename = spa_steal_ptr(filename); this->info.args = args ? strdup(args) : NULL; - spa_list_prepend(&context->module_list, &this->link); + if ((name != NULL && this->info.name == NULL) || + (args != NULL && this->info.args == NULL)) + goto error_strdup_fail; this->global = pw_global_new(context, PW_TYPE_INTERFACE_Module, @@ -272,6 +275,9 @@ error_no_mem: res = -errno; pw_log_error("can't allocate module: %m"); goto error_close; +error_strdup_fail: + res = -errno; + goto error_free_module; error_no_global: res = -errno; pw_log_error("\"%s\": failed to create global: %m", this->info.filename); diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index a4f96cff2..b85956642 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -1580,11 +1580,11 @@ stream_new(struct pw_context *context, const char *name, this = &impl->this; pw_log_debug("%p: new \"%s\"", impl, name); - if (props == NULL) { + if (props == NULL) props = pw_properties_new(PW_KEY_MEDIA_NAME, name, NULL); - } else if (pw_properties_get(props, PW_KEY_MEDIA_NAME) == NULL) { + else if (pw_properties_get(props, PW_KEY_MEDIA_NAME) == NULL) pw_properties_set(props, PW_KEY_MEDIA_NAME, name); - } + if (props == NULL) { res = -errno; goto error_properties; @@ -1610,6 +1610,10 @@ stream_new(struct pw_context *context, const char *name, pw_context_conf_update_props(context, "stream.properties", props); this->name = name ? strdup(name) : NULL; + if (name != NULL && this->name == NULL) { + res = -errno; + goto error_properties; + } this->node_id = SPA_ID_INVALID; spa_ringbuffer_init(&impl->dequeued.ring);