[PATCH v4] coccinelle: semantic patch for missing put_device()

From: Wen Yang
Date: Thu Feb 14 2019 - 01:37:42 EST


The of_find_device_by_node() takes a reference to the underlying device
structure, we should release that reference.
The implementation of this semantic patch is:
In a function, for variables returned by calling of_find_device_by_node(),
a, if it is released by a function such as
put_device()/of_dev_put()/platform_device_put() after the last use,
it is considered that there is no reference leak;
b, if it is passed back to the caller via
dev_get_drvdata()/platform_get_drvdata()/get_device(), etc., the
reference will be released in other functions, and the current function
also considers that there is no reference leak;
c, for the rest of the situation, the current function should release the
reference by calling put_device, this patch will report the
corresponding error message.

By using this semantic patch, we have found some object reference leaks,
such as:
commit 11907e9d3533 ("ASoC: fsl-asoc-card: fix object reference leaks in
fsl_asoc_card_probe")
commit a12085d13997 ("mtd: rawnand: atmel: fix possible object reference leak")
commit 11493f26856a ("mtd: rawnand: jz4780: fix possible object reference leak")

There are still dozens of reference leaks in the current kernel code.

Further, for the case of b, the object returned to other functions may also
have a reference leak, we will continue to develop other cocci scripts to
further check the reference leak.

Signed-off-by: Wen Yang <wen.yang99@xxxxxxxxxx>
Reviewed-by: Julia Lawall <Julia.Lawall@xxxxxxx>
Reviewed-by: Markus Elfring <Markus.Elfring@xxxxxx>
Cc: Julia Lawall <Julia.Lawall@xxxxxxx>
Cc: Gilles Muller <Gilles.Muller@xxxxxxx>
Cc: Nicolas Palix <nicolas.palix@xxxxxxx>
Cc: Michal Marek <michal.lkml@xxxxxxxxxxx>
Cc: Markus Elfring <Markus.Elfring@xxxxxx>
Cc: Masahiro Yamada <yamada.masahiro@xxxxxxxxxxxxx>
Cc: Wen Yang <yellowriver2010@xxxxxxxxxxx>
Cc: cheng.shengyu@xxxxxxxxxx
Cc: cocci@xxxxxxxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
v4->v3:
- add Masahiro Yamada
- omit a blank line
- split the long message parameter
- reduce the number of metavariables
- Describe the implementation of the semantic patch,
explain the scenarios it can detect,
and further software development considerations.
v3->v2:
- reduction of a bit of redundant C code within SmPL search specifications.
- consider the message construction without using the extra Python variable âmsgâ
v2->v1:
- put exists after search, and then drop the when exists below.
- should not use the same e as in the when's below.
- Make a new type metavariable and use it to put a cast on the result of
platform_get_drvdata.

scripts/coccinelle/free/put_device.cocci | 55 ++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 scripts/coccinelle/free/put_device.cocci

diff --git a/scripts/coccinelle/free/put_device.cocci b/scripts/coccinelle/free/put_device.cocci
new file mode 100644
index 0000000..6fd79cf
--- /dev/null
+++ b/scripts/coccinelle/free/put_device.cocci
@@ -0,0 +1,55 @@
+/// Find missing put_device for every of_find_device_by_node.
+///
+// Confidence: Moderate
+// Copyright: (C) 2018-2019 Wen Yang, ZTE. GPLv2.
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual report
+virtual org
+
+@search exists@
+local idexpression id;
+expression x,e,e1;
+position p1,p2;
+type T,T1,T2,T3;
+@@
+
+id = of_find_device_by_node@p1(x)
+... when != e = id
+if (id == NULL || ...) { ... return ...; }
+... when != put_device(&id->dev)
+ when != platform_device_put(id)
+ when != of_dev_put(id)
+ when != if (id) { ... put_device(&id->dev) ... }
+ when != e1 = (T)id
+ when != e1 = &id->dev
+ when != e1 = get_device(&id->dev)
+ when != e1 = (T1)platform_get_drvdata(id)
+(
+ return
+( id
+| (T2)dev_get_drvdata(&id->dev)
+| (T3)platform_get_drvdata(id)
+);
+| return@p2 ...;
+)
+
+@script:python depends on report@
+p1 << search.p1;
+p2 << search.p2;
+@@
+
+coccilib.report.print_report(p2[0],
+ "ERROR: missing put_device;"
+ + " call of_find_device_by_node on line "
+ + p1[0].line
+ + " and return without releasing.")
+
+@script:python depends on org@
+p1 << search.p1;
+p2 << search.p2;
+@@
+
+cocci.print_main("of_find_device_by_node", p1)
+cocci.print_secs("needed put_device", p2)
--
2.9.5