[PATCH] audio/pipewire: Fix stack overflow by moving buffer to heap

Jun Yu posted 1 patch 3 days, 15 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260408012341.16131-1-yujun@kylinos.cn
Maintainers: Gerd Hoffmann <kraxel@redhat.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>
audio/pwaudio.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
[PATCH] audio/pipewire: Fix stack overflow by moving buffer to heap
Posted by Jun Yu 3 days, 15 hours ago
The PWVoice struct was allocating a large 4MB buffer on the stack using
uint8_t buffer[RINGBUFFER_SIZE], which could cause stack overflow.

This commit:
1. Changes the buffer from stack allocation to heap allocation by replacing
   uint8_t buffer[RINGBUFFER_SIZE] with uint8_t *buffer
2. Adds g_malloc() calls in qpw_init_out() and qpw_init_in() to allocate
   the buffer on the heap
3. Adds g_free() in qpw_voice_fini() to properly clean up the buffer
4. Adds error handling for allocation failures

This fix prevents stack overflow while maintaining the same functionality,
as each audio stream (input/output) still gets its own independent buffer
for the ringbuffer operations.

Signed-off-by: Jun Yu <yujun@kylinos.cn>
---
 audio/pwaudio.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index a59c22e60b..ff75ec2af2 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -56,7 +56,7 @@ typedef struct PWVoice {
     uint32_t highwater_mark;
     uint32_t frame_size, req;
     struct spa_ringbuffer ring;
-    uint8_t buffer[RINGBUFFER_SIZE];
+    uint8_t *buffer;
 
     pwvolume volume;
     bool muted;
@@ -532,6 +532,12 @@ qpw_init_out(HWVoiceOut *hw, struct audsettings *as)
     AudiodevPipewirePerDirectionOptions *ppdo = popts->out;
     int r;
 
+    v->buffer = g_malloc(RINGBUFFER_SIZE);
+    if (!v->buffer) {
+        error_report("pipewire: failed to allocate buffer");
+        return -1;
+    }
+
     pw_thread_loop_lock(c->thread_loop);
 
     v->info.format = audfmt_to_pw(as->fmt, as->big_endian);
@@ -551,6 +557,8 @@ qpw_init_out(HWVoiceOut *hw, struct audsettings *as)
                        ppdo->name, SPA_DIRECTION_OUTPUT);
     if (r < 0) {
         pw_thread_loop_unlock(c->thread_loop);
+        g_free(v->buffer);
+        v->buffer = NULL;
         return -1;
     }
 
@@ -579,6 +587,12 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as)
     AudiodevPipewirePerDirectionOptions *ppdo = popts->in;
     int r;
 
+    v->buffer = g_malloc(RINGBUFFER_SIZE);
+    if (!v->buffer) {
+        error_report("pipewire: failed to allocate buffer");
+        return -1;
+    }
+
     pw_thread_loop_lock(c->thread_loop);
 
     v->info.format = audfmt_to_pw(as->fmt, as->big_endian);
@@ -595,6 +609,8 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as)
                        ppdo->name, SPA_DIRECTION_INPUT);
     if (r < 0) {
         pw_thread_loop_unlock(c->thread_loop);
+        g_free(v->buffer);
+        v->buffer = NULL;
         return -1;
     }
 
@@ -619,6 +635,8 @@ qpw_voice_fini(AudioPw *c, PWVoice *v)
     pw_stream_destroy(v->stream);
     v->stream = NULL;
     pw_thread_loop_unlock(c->thread_loop);
+    g_free(v->buffer);
+    v->buffer = NULL;
 }
 
 static void
-- 
2.25.1
Re: [PATCH] audio/pipewire: Fix stack overflow by moving buffer to heap
Posted by Thomas Huth 3 days, 11 hours ago
On 08/04/2026 03.23, Jun Yu wrote:
> The PWVoice struct was allocating a large 4MB buffer on the stack using
> uint8_t buffer[RINGBUFFER_SIZE], which could cause stack overflow.

Which function is this? I.e. where does this get created on the stack?

> This commit:
> 1. Changes the buffer from stack allocation to heap allocation by replacing
>     uint8_t buffer[RINGBUFFER_SIZE] with uint8_t *buffer
> 2. Adds g_malloc() calls in qpw_init_out() and qpw_init_in() to allocate
>     the buffer on the heap
> 3. Adds g_free() in qpw_voice_fini() to properly clean up the buffer
> 4. Adds error handling for allocation failures
> 
> This fix prevents stack overflow while maintaining the same functionality,
> as each audio stream (input/output) still gets its own independent buffer
> for the ringbuffer operations.

Just to double-check: Did you use AI to create this patch? Or just for the 
patch description?

> Signed-off-by: Jun Yu <yujun@kylinos.cn>
> ---
>   audio/pwaudio.c | 20 +++++++++++++++++++-
>   1 file changed, 19 insertions(+), 1 deletion(-)
> 
> diff --git a/audio/pwaudio.c b/audio/pwaudio.c
> index a59c22e60b..ff75ec2af2 100644
> --- a/audio/pwaudio.c
> +++ b/audio/pwaudio.c
> @@ -56,7 +56,7 @@ typedef struct PWVoice {
>       uint32_t highwater_mark;
>       uint32_t frame_size, req;
>       struct spa_ringbuffer ring;
> -    uint8_t buffer[RINGBUFFER_SIZE];
> +    uint8_t *buffer;
>   
>       pwvolume volume;
>       bool muted;
> @@ -532,6 +532,12 @@ qpw_init_out(HWVoiceOut *hw, struct audsettings *as)
>       AudiodevPipewirePerDirectionOptions *ppdo = popts->out;
>       int r;
>   
> +    v->buffer = g_malloc(RINGBUFFER_SIZE);
> +    if (!v->buffer) {

g_malloc never returns NULL.

> +        error_report("pipewire: failed to allocate buffer");
> +        return -1;
> +    }
> +
>       pw_thread_loop_lock(c->thread_loop);
>   
>       v->info.format = audfmt_to_pw(as->fmt, as->big_endian);
> @@ -551,6 +557,8 @@ qpw_init_out(HWVoiceOut *hw, struct audsettings *as)
>                          ppdo->name, SPA_DIRECTION_OUTPUT);
>       if (r < 0) {
>           pw_thread_loop_unlock(c->thread_loop);
> +        g_free(v->buffer);
> +        v->buffer = NULL;
>           return -1;
>       }
>   
> @@ -579,6 +587,12 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as)
>       AudiodevPipewirePerDirectionOptions *ppdo = popts->in;
>       int r;
>   
> +    v->buffer = g_malloc(RINGBUFFER_SIZE);
> +    if (!v->buffer) {

dito.

> +        error_report("pipewire: failed to allocate buffer");
> +        return -1;
> +    }
> +
>       pw_thread_loop_lock(c->thread_loop);
>   
>       v->info.format = audfmt_to_pw(as->fmt, as->big_endian);
> @@ -595,6 +609,8 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as)
>                          ppdo->name, SPA_DIRECTION_INPUT);
>       if (r < 0) {
>           pw_thread_loop_unlock(c->thread_loop);
> +        g_free(v->buffer);
> +        v->buffer = NULL;
>           return -1;
>       }
>   
> @@ -619,6 +635,8 @@ qpw_voice_fini(AudioPw *c, PWVoice *v)
>       pw_stream_destroy(v->stream);
>       v->stream = NULL;
>       pw_thread_loop_unlock(c->thread_loop);
> +    g_free(v->buffer);
> +    v->buffer = NULL;
>   }

  Thomas