Re: devm_ on lists

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Thu, 18 May 2023, Christophe JAILLET wrote:

> Le 18/05/2023 à 09:27, Dan Carpenter a écrit :
> > I sometimes have more ideas than I can handle in a day and my mind
> > resets every night so every morning I am a blank slate like that guy
> > from that movie.
> >
> > So I'm going to start writing them down and adding a hashtag.
> > #StaticCheckerIdeas  I'm going to CC kernel janitors until the Smatch
> > list gets archived on lore.kernel.org
> >
> > There is a bug in ti_sci_probe() where it does:
> >
> > 	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
> > 	...
> > 	list_add_tail(&info->node, &ti_sci_list);
> > 	...
> > 	return of_platform_populate(dev->of_node, NULL, NULL, dev);
> >
> > Idea 1:  If of_platform_populate() fails, then info freed but it's it's
> > still on the the &ti_sci_list list.  Look for list_add of devm_ data
> > and ensure that it's removed from the list before an error code.
> >
> > There are other lifetime issues surrounding devm_ data.  We need a
> > list_del in the release function as well.
> >
> > Idea 2: The other error paths all have clean up so last error path
> > should have clean up too.
> >
> > regards,
> > dan carpenter
> >
>
> Nice!
>
> A really naive:
> @r@
> expression m;
> identifier alloc_fn =~ "devm_";
> identifier list_fn =~ "list_add";
> @@
>
> *	m = alloc_fn(...);
> 	...
> *	list_fn(..., <+... m ...+>, ...);
>
>
> also seems to give some decent results.
> Written as-is, there is a lot of false positive, but is a start.
>
> I'll give it a look.

Here is an attempt that is a bit more defensive than Christophe's:

@@
identifier d =~ "devm";
identifier x;
expression e;
int r != 0;
global idexpression f;
iterator i;
@@


*        e = d(...)
         ...
(
*        list_add_tail(&e->x, &f)
|
*        list_add(&e->x, &f)
)
         ... when != list_del(&e->x)
             when != i(...) { ... list_del(&e->x) ... }
         return r;

Perhaps Christophe's more general list_add pattern is a good idea.

This has false positives when the return value is a variable that actually
contains 0.  These false positives are easy to detect.

This rule requires that the list is a global variable.  That constraint
implies that the rule gives a small number of results that are "easy" to
deal with.

Afterwards, the question is what does one do to deal with them?  If you
remove the line when != i(...) { ... list_del(&e->x) ... }, then one of
the results does have a loop at the end of the function that deletes all
the elements in the list.  That is fine as a solution if the list started
out empty.  Otherwise, I guess one would have to collect another list of
things added to the list along the way, to be able to remove them all in
the failure case.

If the list_add can be moved to a safer place, as Christophe suggests,
then that also seems like a good solution.  But often the allocation and
list_add are in a loop.

There are a lot more results if one replaces the two occurrences of &f by
... The typical result has the list being &a->b where a is a parameter.
Then one would have to trace up the nested callers to check that they are
all destroyed on failure.  That seems painful to do manually, and probably
painful to do with Coccinelle.  Does there exist some smatch code to do
that?

julia


>
>
>
> One of my first match is:diff -u -p drivers/perf/qcom_l2_pmu.c
> /tmp/nothing/perf/qcom_l2_pmu.c
> --- drivers/perf/qcom_l2_pmu.c
> +++ /tmp/nothing/perf/qcom_l2_pmu.c
> @@ -852,12 +852,10 @@ static int l2_cache_pmu_probe_cluster(st
>  		return err;
>  	}
>
> -	cluster = devm_kzalloc(&pdev->dev, sizeof(*cluster), GFP_KERNEL);
>  	if (!cluster)
>  		return -ENOMEM;
>
>  	INIT_LIST_HEAD(&cluster->next);
> -	list_add(&cluster->next, &l2cache_pmu->clusters);
>  	cluster->cluster_id = fw_cluster_id;
>
>  	irq = platform_get_irq(sdev, 0);
>
> which looks like a real one.
>
> list_add() should be at the very end of the probe in order not to "corrupt"
> the l2cache_pmu list.
>
>
>
> Adding Julia if she wishes to dig it a little more with coccinelle.
>
> CJ
>

[Index of Archives]     [Kernel Development]     [Kernel Announce]     [Kernel Newbies]     [Linux Networking Development]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Device Mapper]

  Powered by Linux