Find and convert uses of IS_ERR() plus NULL check to IS_ERR_OR_NULL().

There are several cases where `!ptr && WARN_ON[_ONCE](IS_ERR(ptr))` is
used:
- arch/x86/kernel/callthunks.c:215 WARN_ON_ONCE
- drivers/clk/clk.c:4561 WARN_ON_ONCE
- drivers/interconnect/core.c:793 WARN_ON
- drivers/reset/core.c:718 WARN_ON
The change is not 100% semantical equivalent as the warning will now
also happen when the pointer is NULL.

To: Julia Lawall <[email protected]>
To: Nicolas Palix <[email protected]>
Cc: [email protected]
Cc: [email protected]

---
drivers/clocksource/mips-gic-timer.c:283 looks suspicious: ret != clk,
but Daniel Lezcano verified it as cottect.

There are some cases where the checks are part of a larger expression:
- mm/kmemleak.c:1095
- mm/kmemleak.c:1155
- mm/kmemleak.c:1173
- mm/kmemleak.c:1290
- mm/kmemleak.c:1328
- mm/kmemleak.c:1241
- mm/kmemleak.c:1310
- mm/kmemleak.c:1258
- net/netlink/af_netlink.c:2670
Thanks to Julia Lawall for the help to also handle them.

Signed-off-by: Philipp Hahn <[email protected]>
---
 scripts/coccinelle/api/is_err_or_null.cocci | 125 ++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git a/scripts/coccinelle/api/is_err_or_null.cocci 
b/scripts/coccinelle/api/is_err_or_null.cocci
new file mode 100644
index 
0000000000000000000000000000000000000000..7a430eadccd9f9f28b1711d67dd87a817a45bd52
--- /dev/null
+++ b/scripts/coccinelle/api/is_err_or_null.cocci
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Use IF_ERR_OR_NULL() instead of IS_ERR() plus a check for (not) NULL
+///
+// Copyright: (C) 2026 Philipp Hahn, FRITZ! Technology GmbH.
+// Confidence: High
+// Options: --no-includes --include-headers
+// Keywords: IS_ERR, IS_ERR_OR_NULL
+
+virtual patch
+virtual report
+virtual org
+
+@p1 depends on patch@
+expression E;
+@@
+(
+-      E != NULL && !IS_ERR(E)
++      !IS_ERR_OR_NULL(E)
+|
+-      E == NULL || IS_ERR(E)
++      IS_ERR_OR_NULL(E)
+|
+-      !IS_ERR(E) && E != NULL
++      !IS_ERR_OR_NULL(E)
+|
+-      IS_ERR(E) || E == NULL
++      IS_ERR_OR_NULL(E)
+)
+
+@p2 depends on patch@
+expression E;
+@@
+(
+-      E == NULL || WARN_ON(IS_ERR(E))
++      WARN_ON(IS_ERR_OR_NULL(E))
+|
+-      E == NULL || WARN_ON_ONCE(IS_ERR(E))
++      WARN_ON_ONCE(IS_ERR_OR_NULL(E))
+)
+
+@p3 depends on patch@
+expression E,e1;
+@@
+(
+-      e1 && E != NULL && !IS_ERR(E)
++      e1 && !IS_ERR_OR_NULL(E)
+|
+-      e1 || E == NULL || IS_ERR(E)
++      e1 || IS_ERR_OR_NULL(E)
+|
+-      e1 && !IS_ERR(E) && E != NULL
++      e1 && !IS_ERR_OR_NULL(E)
+|
+-      e1 || IS_ERR(E) || E == NULL
++      e1 || IS_ERR_OR_NULL(E)
+)
+
+@r1 depends on report || org@
+expression E;
+position p;
+@@
+(
+       E != NULL && ... && !IS_ERR@p(E)
+|
+       E == NULL || ... || IS_ERR@p(E)
+|
+       !IS_ERR@p(E) && ... && E != NULL
+|
+       IS_ERR@p(E) || ... || E == NULL
+)
+
+@script:python depends on report@
+p << r1.p;
+@@
+coccilib.report.print_report(p[0], "opportunity for IS_ERR_OR_NULL()")
+
+@script:python depends on org@
+p << r1.p;
+@@
+coccilib.org.print_todo(p[0], "opportunity for IS_ERR_OR_NULL()")
+
+@p4 depends on patch@
+identifier I;
+expression E;
+@@
+(
+-      (I = E) != NULL && !IS_ERR(I)
++      !IS_ERR_OR_NULL((I = E))
+|
+-      (I = E) == NULL || IS_ERR(I)
++      IS_ERR_OR_NULL((I = E))
+)
+
+@r2 depends on report || org@
+identifier I;
+expression E;
+position p;
+@@
+(
+*      (I = E) != NULL && ... && !IS_ERR@p(I)
+|
+*      (I = E) == NULL || ... || IS_ERR@p(I)
+)
+
+@script:python depends on report@
+p << r2.p;
+@@
+coccilib.report.print_report(p[0], "opportunity for IS_ERR_OR_NULL()")
+
+@script:python depends on org@
+p << r2.p;
+@@
+coccilib.org.print_todo(p[0], "opportunity for IS_ERR_OR_NULL()")
+
+@p5 depends on patch disable unlikely @
+expression E;
+@@
+-\( likely \| unlikely \)(
+(
+ IS_ERR_OR_NULL(E)
+|
+ !IS_ERR_OR_NULL(E)
+)
+-)

-- 
2.43.0


Reply via email to