Re: [PATCH] ASoC: meson: axg-tdm-formatter: Use guard() for mutex locks

Jerome Brunet <[email protected]>
Newsgroups org.infradead.lists.linux-amlogic,dev.linux.lists.sashiko-reviews
Message-ID <[email protected]>
On mer. 10 juin 2026 at 10:32, [email protected] wrote:

> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] If `axg_tdm_formatter_attach()` fails to enable the formatter
> (e.g. when trying to catch up to an already running stream), it returns an
> error and skips `list_add_tail()`. However, the DAPM framework will log the
> error but still mark the widget as powered up. Later, during teardown or
> routing changes, DAPM will call `axg_tdm_formatter_dettach()`, which
> blindly executes `list_del(&formatter->list)`. Since the list head is
> zero-initialized by `devm_kzalloc` and was never added to the list,
> `list_del()` will dereference NULL pointers, causing a kernel crash.
> - [High] The return value of `axg_tdm_stream_start()` is completely ignored
> in `axg_tdm_iface_trigger()`. If the stream fails to start (for example,
> due to a failure in `axg_tdm_formatter_enable()`), `axg_tdm_stream_start()`
> correctly returns an error code. However, `axg_tdm_iface_trigger()` drops
> this error and unconditionally returns 0.
> --
>
> commit d9e23c7e7ade1061d83943c614a45fe952dec33d
> Author: bui duc phuc <[email protected]>
>
> ASoC: meson: axg-tdm-formatter: Use guard() for mutex locks
>
> Clean up the code using guard() for mutex locks.
> Merely code refactoring, and no behavior change.
>
>> diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c
>> --- a/sound/soc/meson/axg-tdm-formatter.c
>> +++ b/sound/soc/meson/axg-tdm-formatter.c
>> @@ -157,20 +157,19 @@ static int axg_tdm_formatter_attach(struct axg_tdm_formatter *formatter)
>>  	struct axg_tdm_stream *ts = formatter->stream;
>>  	int ret = 0;
>>  
>> -	mutex_lock(&ts->lock);
>> +	guard(mutex)(&ts->lock);
>>  
>>  	/* Catch up if the stream is already running when we attach */
>>  	if (ts->ready) {
>>  		ret = axg_tdm_formatter_enable(formatter);
>>  		if (ret) {
>>  			pr_err("failed to enable formatter\n");
>> -			goto out;
>> +			return ret;
>>  		}
>>  	}
>>  
>>  	list_add_tail(&formatter->list, &ts->formatter_list);
>> -out:
>> -	mutex_unlock(&ts->lock);
>> +
>>  	return ret;
>>  }
>
> [Severity: High]
> This is a pre-existing issue, but if axg_tdm_formatter_enable() fails,
> this error path returns early and skips list_add_tail().

This is path the very few have tested since it only happens when
someone is playing around the routing kcontrol on a running
stream. Still it is supposed to work.

>
> If the DAPM framework logs the error but still marks the widget as powered
> up, it might later call axg_tdm_formatter_dettach() during teardown or
> routing changes.

Ok but the IF is important here.

A widget that failed PRE_PMU event should not receive a PRE_PMD one.
so it makes to unwind anything on error.

>
> Since axg_tdm_formatter_dettach() blindly executes:
>
>     scoped_guard(mutex, &ts->lock)
>         list_del(&formatter->list);
>
> Does this result in a NULL pointer dereference because the list head is
> zero-initialized and was never actually added to the list?
>
> [ ... ]
>> @@ -330,7 +328,7 @@ int axg_tdm_stream_start(struct axg_tdm_stream *ts)
>>  	struct axg_tdm_formatter *formatter;
>>  	int ret = 0;
>>  
>> -	mutex_lock(&ts->lock);
>> +	guard(mutex)(&ts->lock);
>>  	ts->ready = true;
>>  
>>  	/* Start all the formatters attached to the stream */
>> @@ -338,12 +336,10 @@ int axg_tdm_stream_start(struct axg_tdm_stream *ts)
>>  		ret = axg_tdm_formatter_enable(formatter);
>>  		if (ret) {
>>  			pr_err("failed to start tdm stream\n");
>> -			goto out;
>> +			return ret;
>>  		}
>>  	}
>>  
>> -out:
>> -	mutex_unlock(&ts->lock);
>>  	return ret;
>>  }
>
> [Severity: High]
> This isn't a bug introduced by this patch, but is it possible for the
> return value of axg_tdm_stream_start() to be lost?
>
> Looking at axg_tdm_iface_trigger() in sound/soc/meson/axg-tdm-interface.c:
>
>     switch (cmd) {
>     case SNDRV_PCM_TRIGGER_START:
>     case SNDRV_PCM_TRIGGER_RESUME:
>     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>         axg_tdm_stream_start(ts);
>         break;
>
> If axg_tdm_stream_start() returns an error code here, the error isn't
> propagated back to ALSA. Does this mask the initialization failure and
> cause the framework to silently fail, leaving applications to hang while
> waiting for period elapsed events?

2 things here:

1) This is a DPCM backend so no "period elapsed events" here. This would
happen on the FIFO frontends

2) The return code is a grey area here. There could be multiple
formatters attached, this is mostly why the error code is ignored, so a
working backend would continue to operate if another fail. That's the
idea at least. 

-- 
Jerome

_______________________________________________
linux-amlogic mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-amlogic
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.