diff mbox series

[1/2] tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() in case of error

Message ID e4359d5ef206f5b349c1d15a515a1205e78dda55.1686285892.git.christophe.jaillet@wanadoo.fr
State New
Headers show
Series [1/2] tty: serial: samsung_tty: Fix a memory leak in s3c24xx_serial_getclk() in case of error | expand

Commit Message

Christophe JAILLET June 9, 2023, 4:45 a.m. UTC
If clk_get_rate() fails, the clk that has just been allocated needs to be
freed.

Fixes: 5f5a7a5578c5 ("serial: samsung: switch to clkdev based clock lookup")
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
---
 drivers/tty/serial/samsung_tty.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Comments

Andi Shyti June 10, 2023, 10:39 a.m. UTC | #1
Hi Christophe,

On Fri, Jun 09, 2023 at 06:45:39AM +0200, Christophe JAILLET wrote:
> When the best clk is searched, we iterate over all possible clk.
> 
> If we find a better match, the previous one, if any, needs to be freed.
> If a better match has already been found, we still need to free the new
> one, otherwise it leaks.
> 
> Fixes: 5f5a7a5578c5 ("serial: samsung: switch to clkdev based clock lookup")
> Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
> ---
> This patch is speculative. Review with care.
> 
> I think that some clk_put() are also missing somewhere else in the driver
> but won't be able to investigate further.
> ---
>  drivers/tty/serial/samsung_tty.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
> index dd751e7010e3..c07877dd25fa 100644
> --- a/drivers/tty/serial/samsung_tty.c
> +++ b/drivers/tty/serial/samsung_tty.c
> @@ -1488,10 +1488,18 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
>  			calc_deviation = -calc_deviation;
>  
>  		if (calc_deviation < deviation) {
> +			/*
> +			 * If we find a better clk, release the previous one, if
> +			 * any.
> +			 */
> +			if (!IS_ERR(*best_clk))

what is the case when *best_clk has an error in it?

Andi

> +				clk_put(*best_clk);
>  			*best_clk = clk;
>  			best_quot = quot;
>  			*clk_num = cnt;
>  			deviation = calc_deviation;
> +		} else {
> +			clk_put(clk);
>  		}
>  	}
>  
> -- 
> 2.34.1
>
Andi Shyti June 10, 2023, 10:57 a.m. UTC | #2
Hi Krzysztof,

> On Sat, Jun 10, 2023 at 12:45:53PM +0200, Krzysztof Kozlowski wrote:
> On 10/06/2023 12:39, Andi Shyti wrote:
> > Hi Christophe,
> > 
> > On Fri, Jun 09, 2023 at 06:45:39AM +0200, Christophe JAILLET wrote:
> >> When the best clk is searched, we iterate over all possible clk.
> >>
> >> If we find a better match, the previous one, if any, needs to be freed.
> >> If a better match has already been found, we still need to free the new
> >> one, otherwise it leaks.
> >>
> >> Fixes: 5f5a7a5578c5 ("serial: samsung: switch to clkdev based clock lookup")
> >> Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
> >> ---
> >> This patch is speculative. Review with care.
> >>
> >> I think that some clk_put() are also missing somewhere else in the driver
> >> but won't be able to investigate further.
> >> ---
> >>  drivers/tty/serial/samsung_tty.c | 8 ++++++++
> >>  1 file changed, 8 insertions(+)
> >>
> >> diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
> >> index dd751e7010e3..c07877dd25fa 100644
> >> --- a/drivers/tty/serial/samsung_tty.c
> >> +++ b/drivers/tty/serial/samsung_tty.c
> >> @@ -1488,10 +1488,18 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
> >>  			calc_deviation = -calc_deviation;
> >>  
> >>  		if (calc_deviation < deviation) {
> >> +			/*
> >> +			 * If we find a better clk, release the previous one, if
> >> +			 * any.
> >> +			 */
> >> +			if (!IS_ERR(*best_clk))
> > 
> > what is the case when *best_clk has an error in it?
> 
> The initial one? Open the place where the function is being called.

Right!

Reviewed-by: Andi Shyti <andi.shyti@kernel.org> 

Andi

> 
> Best regards,
> Krzysztof
>
Christophe JAILLET June 10, 2023, 2:07 p.m. UTC | #3
Le 10/06/2023 à 12:26, Andi Shyti a écrit :
>> @@ -1459,8 +1459,10 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
>>   			continue;
>>   
>>   		rate = clk_get_rate(clk);
>> -		if (!rate)
>> +		if (!rate) {
>> +			clk_put(clk);
>>   			continue;
> 
> could you also print an error here?
> 

Is:
	dev_err(ourport->port.dev,
		"Failed to get clock rate for %s.\n", clkname);

fine for you?

CJ
Krzysztof Kozlowski June 10, 2023, 4:23 p.m. UTC | #4
On 10/06/2023 16:54, Andi Shyti wrote:
> On Sat, Jun 10, 2023 at 04:07:51PM +0200, Christophe JAILLET wrote:
>> Le 10/06/2023 à 12:26, Andi Shyti a écrit :
>>>> @@ -1459,8 +1459,10 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
>>>>   			continue;
>>>>   		rate = clk_get_rate(clk);
>>>> -		if (!rate)
>>>> +		if (!rate) {
>>>> +			clk_put(clk);
>>>>   			continue;
>>>
>>> could you also print an error here?
>>>
>>
>> Is:
>> 	dev_err(ourport->port.dev,
>> 		"Failed to get clock rate for %s.\n", clkname);

Why do we need it? Most of other users of clk_get_rate() don't print.
Probably because such condition is highly unlikely if not impossible.
This makes simple function unnecessarily bigger...

Best regards,
Krzysztof
Krzysztof Kozlowski June 10, 2023, 5:32 p.m. UTC | #5
On 10/06/2023 19:10, Andi Shyti wrote:
> On Sat, Jun 10, 2023 at 06:23:58PM +0200, Krzysztof Kozlowski wrote:
>> On 10/06/2023 16:54, Andi Shyti wrote:
>>> On Sat, Jun 10, 2023 at 04:07:51PM +0200, Christophe JAILLET wrote:
>>>> Le 10/06/2023 à 12:26, Andi Shyti a écrit :
>>>>>> @@ -1459,8 +1459,10 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
>>>>>>   			continue;
>>>>>>   		rate = clk_get_rate(clk);
>>>>>> -		if (!rate)
>>>>>> +		if (!rate) {
>>>>>> +			clk_put(clk);
>>>>>>   			continue;
>>>>>
>>>>> could you also print an error here?
>>>>>
>>>>
>>>> Is:
>>>> 	dev_err(ourport->port.dev,
>>>> 		"Failed to get clock rate for %s.\n", clkname);
>>
>> Why do we need it? Most of other users of clk_get_rate() don't print.
> 
> that's not a reason not to print it.

This is the reason, because it was the conscious choice - not to print,
otherwise drivers are unreadable.

> 
>> Probably because such condition is highly unlikely if not impossible.
> 
> still... that's not a reason not to print it.

It is a reason not to print it in the driver. Code readability is more
important than adding error messages for every possible case in the driver.

> 
> All errors are unlikely and if it's unlikely, why there is no
> unlikely(!rate)? Which doesn't improve the reason not to print
> it.
> 
> The more unlikely, the lauder you need to be:
> 
> WARN_ON(!rate)... maybe too much!
> BUG_ON(!rate)... way too much!
> 
> But these are inversely proportional to the likeliness of the
> error.
> 
>> This makes simple function unnecessarily bigger...
> 
> and... that's not a reason not to print it :)

This is the reason not to print it in the driver, because it makes the
code less maintainable. Such unlikely errors should be handled by core,
not by every driver. If this error message here is reasonable, I would
argue that it is reasonable to add it to other places... try doing it.
You will see to what silly code it leads.

It's like adding dev_err to regmap_mmio read/write failures - code will
be difficult to read.

Best regards,
Krzysztof
Christophe JAILLET June 10, 2023, 5:40 p.m. UTC | #6
Le 10/06/2023 à 19:10, Andi Shyti a écrit :
> On Sat, Jun 10, 2023 at 06:23:58PM +0200, Krzysztof Kozlowski wrote:
>> On 10/06/2023 16:54, Andi Shyti wrote:
>>> On Sat, Jun 10, 2023 at 04:07:51PM +0200, Christophe JAILLET wrote:
>>>> Le 10/06/2023 à 12:26, Andi Shyti a écrit :
>>>>>> @@ -1459,8 +1459,10 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
>>>>>>    			continue;
>>>>>>    		rate = clk_get_rate(clk);
>>>>>> -		if (!rate)
>>>>>> +		if (!rate) {
>>>>>> +			clk_put(clk);
>>>>>>    			continue;
>>>>>
>>>>> could you also print an error here?
>>>>>
>>>>
>>>> Is:
>>>> 	dev_err(ourport->port.dev,
>>>> 		"Failed to get clock rate for %s.\n", clkname);
>>
>> Why do we need it? Most of other users of clk_get_rate() don't print.
> 
> that's not a reason not to print it.
> 
>> Probably because such condition is highly unlikely if not impossible.
> 
> still... that's not a reason not to print it.
> 
> All errors are unlikely and if it's unlikely, why there is no
> unlikely(!rate)? Which doesn't improve the reason not to print
> it.
> 
> The more unlikely, the lauder you need to be:
> 
> WARN_ON(!rate)... maybe too much!
> BUG_ON(!rate)... way too much!
> 
> But these are inversely proportional to the likeliness of the
> error.
> 
>> This makes simple function unnecessarily bigger...
> 
> and... that's not a reason not to print it :)
> 
> If it's needed, it's needed. If we are considering the error,
> then we need to treat it as an error.
> 
> In any case, I'm not strong with it, indeed, I r-b it anyway. I
> personally prefer and suggested printing the error. Up to
> Christophe.

git grep -A5 clk_get_rate | grep dev_err | wc -l
173
git grep clk_get_rate | wc -l
1464

(+ Krzysztof's argumentation)

So lets go for v1.

Can v1 be taken as is?
(knowing that I don't really care about the new 3/3 related to abs())

Or should I send a v3 to ease the process?

CJ


> 
> Thanks,
> Andi
>
Dan Carpenter June 12, 2023, 4:53 a.m. UTC | #7
On Sat, Jun 10, 2023 at 07:10:15PM +0200, Andi Shyti wrote:
> All errors are unlikely and if it's unlikely, why there is no
> unlikely(!rate)?

The likely/unlikely() annotations help performance at the expense of
readability.  If they improved readability every if statement would have
them.  They should only be used if it makes a difference in a benchmark.
I think I have heard other people say the rule is that they shouldn't be
used in the drivers/ directory.

Also the other thing to consider is that quite often GCC is clever
enough to figure out which paths are success paths and which are failure
paths.  So sometimes adding the annotation is redundant.

regards,
dan carpenter
diff mbox series

Patch

diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 2a7520ad3abd..dd751e7010e3 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -1459,8 +1459,10 @@  static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
 			continue;
 
 		rate = clk_get_rate(clk);
-		if (!rate)
+		if (!rate) {
+			clk_put(clk);
 			continue;
+		}
 
 		if (ourport->info->has_divslot) {
 			unsigned long div = rate / req_baud;