audio/pwaudio.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
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
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
© 2016 - 2026 Red Hat, Inc.