Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Remove casting the values returned by memory allocation functions
/// like kmalloc, kzalloc, kmem_cache_alloc, kmem_cache_zalloc etc.
///
//# This makes an effort to find cases of casting of values returned by
//# kmalloc, kzalloc, kcalloc, kmem_cache_alloc, kmem_cache_zalloc,
//# kmem_cache_alloc_node, kmalloc_node and kzalloc_node and removes
//# the casting as it is not required. The result in the patch case may
//# need some reformatting.
//
// Confidence: High
// Copyright: (C) 2014 Himangi Saraogi
// Copyright: (C) 2017 Himanshu Jha
// Comments:
// Options: --no-includes --include-headers
//
virtual context
virtual patch
virtual org
virtual report
@initialize:python@
@@
import re
pattern = '__'
m = re.compile(pattern)
@r1 depends on context || patch@
type T;
@@
(T *)
\(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|
kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|vmalloc\|vzalloc\|
dma_alloc_coherent\|devm_kmalloc\|devm_kzalloc\|
kvmalloc\|kvzalloc\|kvmalloc_node\|kvzalloc_node\|pci_alloc_consistent\|
pci_zalloc_consistent\|kmem_alloc\|kmem_zalloc\|kmem_zone_alloc\|
kmem_zone_zalloc\|vmalloc_node\|vzalloc_node\)(...)
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@script:python depends on context@
t << r1.T;
@@
if m.search(t) != None:
cocci.include_match(False)
@depends on context && r1@
type r1.T;
@@
* (T *)
\(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|
kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|vmalloc\|vzalloc\|
dma_alloc_coherent\|devm_kmalloc\|devm_kzalloc\|
kvmalloc\|kvzalloc\|kvmalloc_node\|kvzalloc_node\|pci_alloc_consistent\|
pci_zalloc_consistent\|kmem_alloc\|kmem_zalloc\|kmem_zone_alloc\|
kmem_zone_zalloc\|vmalloc_node\|vzalloc_node\)(...)
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@script:python depends on patch@
t << r1.T;
@@
if m.search(t) != None:
cocci.include_match(False)
@depends on patch && r1@
type r1.T;
@@
- (T *)
\(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|
kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|vmalloc\|vzalloc\|
dma_alloc_coherent\|devm_kmalloc\|devm_kzalloc\|
kvmalloc\|kvzalloc\|kvmalloc_node\|kvzalloc_node\|pci_alloc_consistent\|
pci_zalloc_consistent\|kmem_alloc\|kmem_zalloc\|kmem_zone_alloc\|
kmem_zone_zalloc\|vmalloc_node\|vzalloc_node\)(...)
//----------------------------------------------------------
// For org and report mode
//----------------------------------------------------------
@r2 depends on org || report@
type T;
position p;
@@
(T@p *)
\(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|
kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|vmalloc\|vzalloc\|
dma_alloc_coherent\|devm_kmalloc\|devm_kzalloc\|
kvmalloc\|kvzalloc\|kvmalloc_node\|kvzalloc_node\|pci_alloc_consistent\|
pci_zalloc_consistent\|kmem_alloc\|kmem_zalloc\|kmem_zone_alloc\|
kmem_zone_zalloc\|vmalloc_node\|vzalloc_node\)(...)
@script:python depends on org@
p << r2.p;
t << r2.T;
@@
if m.search(t) != None:
cocci.include_match(False)
else:
coccilib.org.print_safe_todo(p[0], t)
@script:python depends on report@
p << r2.p;
t << r2.T;
@@
if m.search(t) != None:
cocci.include_match(False)
else:
msg="WARNING: casting value returned by memory allocation function to (%s *) is useless." % (t)
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Use *_pool_zalloc rather than *_pool_alloc followed by memset with 0
///
// Copyright: (C) 2015 Intel Corp.
// Options: --no-includes --include-headers
//
// Keywords: dma_pool_zalloc, pci_pool_zalloc
//
virtual context
virtual patch
virtual org
virtual report
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@depends on context@
expression x;
statement S;
@@
* x = \(dma_pool_alloc\|pci_pool_alloc\)(...);
if ((x==NULL) || ...) S
* memset(x,0, ...);
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@depends on patch@
expression x;
expression a,b,c;
statement S;
@@
- x = dma_pool_alloc(a,b,c);
+ x = dma_pool_zalloc(a,b,c);
if ((x==NULL) || ...) S
- memset(x,0,...);
@depends on patch@
expression x;
expression a,b,c;
statement S;
@@
- x = pci_pool_alloc(a,b,c);
+ x = pci_pool_zalloc(a,b,c);
if ((x==NULL) || ...) S
- memset(x,0,...);
//----------------------------------------------------------
// For org and report mode
//----------------------------------------------------------
@r depends on org || report@
expression x;
expression a,b,c;
statement S;
position p;
@@
x = @p\(dma_pool_alloc\|pci_pool_alloc\)(a,b,c);
if ((x==NULL) || ...) S
memset(x,0, ...);
@script:python depends on org@
p << r.p;
x << r.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r.p;
x << r.x;
@@
msg="WARNING: *_pool_zalloc should be used for %s, instead of *_pool_alloc/memset" % (x)
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,411 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Use zeroing allocator rather than allocator followed by memset with 0
///
/// This considers some simple cases that are common and easy to validate
/// Note in particular that there are no ...s in the rule, so all of the
/// matched code has to be contiguous
///
// Confidence: High
// Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU.
// Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6.
// Copyright: (C) 2017 Himanshu Jha
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
//
// Keywords: kmalloc, kzalloc
// Version min: < 2.6.12 kmalloc
// Version min: 2.6.14 kzalloc
//
virtual context
virtual patch
virtual org
virtual report
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@depends on context@
type T, T2;
expression x;
expression E1;
statement S;
@@
* x = (T)\(kmalloc(E1, ...)\|vmalloc(E1)\|dma_alloc_coherent(...,E1,...)\|
kmalloc_node(E1, ...)\|kmem_cache_alloc(...)\|kmem_alloc(E1, ...)\|
devm_kmalloc(...,E1,...)\|kvmalloc(E1, ...)\|kvmalloc_node(E1,...)\);
if ((x==NULL) || ...) S
* memset((T2)x,0,E1);
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@depends on patch@
type T, T2;
expression x;
expression E1,E2,E3,E4;
statement S;
@@
(
- x = kmalloc(E1,E2);
+ x = kzalloc(E1,E2);
|
- x = (T *)kmalloc(E1,E2);
+ x = kzalloc(E1,E2);
|
- x = (T)kmalloc(E1,E2);
+ x = (T)kzalloc(E1,E2);
|
- x = vmalloc(E1);
+ x = vzalloc(E1);
|
- x = (T *)vmalloc(E1);
+ x = vzalloc(E1);
|
- x = (T)vmalloc(E1);
+ x = (T)vzalloc(E1);
|
- x = kmalloc_node(E1,E2,E3);
+ x = kzalloc_node(E1,E2,E3);
|
- x = (T *)kmalloc_node(E1,E2,E3);
+ x = kzalloc_node(E1,E2,E3);
|
- x = (T)kmalloc_node(E1,E2,E3);
+ x = (T)kzalloc_node(E1,E2,E3);
|
- x = kmem_cache_alloc(E3,E4);
+ x = kmem_cache_zalloc(E3,E4);
|
- x = (T *)kmem_cache_alloc(E3,E4);
+ x = kmem_cache_zalloc(E3,E4);
|
- x = (T)kmem_cache_alloc(E3,E4);
+ x = (T)kmem_cache_zalloc(E3,E4);
|
- x = kmem_alloc(E1,E2);
+ x = kmem_zalloc(E1,E2);
|
- x = (T *)kmem_alloc(E1,E2);
+ x = kmem_zalloc(E1,E2);
|
- x = (T)kmem_alloc(E1,E2);
+ x = (T)kmem_zalloc(E1,E2);
|
- x = devm_kmalloc(E2,E1,E3);
+ x = devm_kzalloc(E2,E1,E3);
|
- x = (T *)devm_kmalloc(E2,E1,E3);
+ x = devm_kzalloc(E2,E1,E3);
|
- x = (T)devm_kmalloc(E2,E1,E3);
+ x = (T)devm_kzalloc(E2,E1,E3);
|
- x = kvmalloc(E1,E2);
+ x = kvzalloc(E1,E2);
|
- x = (T *)kvmalloc(E1,E2);
+ x = kvzalloc(E1,E2);
|
- x = (T)kvmalloc(E1,E2);
+ x = (T)kvzalloc(E1,E2);
|
- x = kvmalloc_node(E1,E2,E3);
+ x = kvzalloc_node(E1,E2,E3);
|
- x = (T *)kvmalloc_node(E1,E2,E3);
+ x = kvzalloc_node(E1,E2,E3);
|
- x = (T)kvmalloc_node(E1,E2,E3);
+ x = (T)kvzalloc_node(E1,E2,E3);
)
if ((x==NULL) || ...) S
- memset((T2)x,0,E1);
@depends on patch@
type T, T2;
expression x;
expression E1,E2,E3,E4;
statement S;
@@
x = (T)dma_alloc_coherent(E1, E2, E3, E4);
if ((x==NULL) || ...) S
- memset((T2)x, 0, E2);
//----------------------------------------------------------
// For org mode
//----------------------------------------------------------
@r depends on org || report@
type T, T2;
expression x;
expression E1,E2;
statement S;
position p;
@@
x = (T)kmalloc@p(E1,E2);
if ((x==NULL) || ...) S
memset((T2)x,0,E1);
@script:python depends on org@
p << r.p;
x << r.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r.p;
x << r.x;
@@
msg="WARNING: kzalloc should be used for %s, instead of kmalloc/memset" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
@r1 depends on org || report@
type T, T2;
expression x;
expression E1;
statement S;
position p;
@@
x = (T)vmalloc@p(E1);
if ((x==NULL) || ...) S
memset((T2)x,0,E1);
@script:python depends on org@
p << r1.p;
x << r1.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r1.p;
x << r1.x;
@@
msg="WARNING: vzalloc should be used for %s, instead of vmalloc/memset" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
@r2 depends on org || report@
type T, T2;
expression x;
expression E1,E2,E3,E4;
statement S;
position p;
@@
x = (T)dma_alloc_coherent@p(E1,E2,E3,E4);
if ((x==NULL) || ...) S
memset((T2)x,0,E2);
@script:python depends on org@
p << r2.p;
x << r2.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r2.p;
x << r2.x;
@@
msg="WARNING: dma_alloc_coherent used in %s already zeroes out memory, so memset is not needed" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
@r3 depends on org || report@
type T, T2;
expression x;
expression E1,E2,E3;
statement S;
position p;
@@
x = (T)kmalloc_node@p(E1,E2,E3);
if ((x==NULL) || ...) S
memset((T2)x,0,E1);
@script:python depends on org@
p << r3.p;
x << r3.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r3.p;
x << r3.x;
@@
msg="WARNING: kzalloc_node should be used for %s, instead of kmalloc_node/memset" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
@r4 depends on org || report@
type T, T2;
expression x;
expression E1,E2,E3;
statement S;
position p;
@@
x = (T)kmem_cache_alloc@p(E2,E3);
if ((x==NULL) || ...) S
memset((T2)x,0,E1);
@script:python depends on org@
p << r4.p;
x << r4.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r4.p;
x << r4.x;
@@
msg="WARNING: kmem_cache_zalloc should be used for %s, instead of kmem_cache_alloc/memset" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
@r5 depends on org || report@
type T, T2;
expression x;
expression E1,E2;
statement S;
position p;
@@
x = (T)kmem_alloc@p(E1,E2);
if ((x==NULL) || ...) S
memset((T2)x,0,E1);
@script:python depends on org@
p << r5.p;
x << r5.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r5.p;
x << r5.x;
@@
msg="WARNING: kmem_zalloc should be used for %s, instead of kmem_alloc/memset" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
@r6 depends on org || report@
type T, T2;
expression x;
expression E1,E2,E3;
statement S;
position p;
@@
x = (T)devm_kmalloc@p(E2,E1,E3);
if ((x==NULL) || ...) S
memset((T2)x,0,E1);
@script:python depends on org@
p << r6.p;
x << r6.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r6.p;
x << r6.x;
@@
msg="WARNING: devm_kzalloc should be used for %s, instead of devm_kmalloc/memset" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
@r7 depends on org || report@
type T, T2;
expression x;
expression E1,E2;
statement S;
position p;
@@
x = (T)kvmalloc@p(E1,E2);
if ((x==NULL) || ...) S
memset((T2)x,0,E1);
@script:python depends on org@
p << r7.p;
x << r7.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r7.p;
x << r7.x;
@@
msg="WARNING: kvzalloc should be used for %s, instead of kvmalloc/memset" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
@r9 depends on org || report@
type T, T2;
expression x;
expression E1,E2,E3;
statement S;
position p;
@@
x = (T)kvmalloc_node@p(E1,E2,E3);
if ((x==NULL) || ...) S
memset((T2)x,0,E1);
@script:python depends on org@
p << r9.p;
x << r9.x;
@@
msg="%s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r9.p;
x << r9.x;
@@
msg="WARNING: kvzalloc_node should be used for %s, instead of kvmalloc_node/memset" % (x)
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,130 @@
// SPDX-License-Identifier: GPL-2.0-only
// Check if refcount_t type and API should be used
// instead of atomic_t type when dealing with refcounters
//
// Copyright (c) 2016-2017, Elena Reshetova, Intel Corporation
//
// Confidence: Moderate
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --include-headers --very-quiet
virtual report
@r1 exists@
identifier a, x;
position p1, p2;
identifier fname =~ ".*free.*";
identifier fname2 =~ ".*destroy.*";
identifier fname3 =~ ".*del.*";
identifier fname4 =~ ".*queue_work.*";
identifier fname5 =~ ".*schedule_work.*";
identifier fname6 =~ ".*call_rcu.*";
@@
(
atomic_dec_and_test@p1(&(a)->x)
|
atomic_dec_and_lock@p1(&(a)->x, ...)
|
atomic_long_dec_and_lock@p1(&(a)->x, ...)
|
atomic_long_dec_and_test@p1(&(a)->x)
|
atomic64_dec_and_test@p1(&(a)->x)
|
local_dec_and_test@p1(&(a)->x)
)
...
(
fname@p2(a, ...);
|
fname2@p2(...);
|
fname3@p2(...);
|
fname4@p2(...);
|
fname5@p2(...);
|
fname6@p2(...);
)
@script:python depends on report@
p1 << r1.p1;
p2 << r1.p2;
@@
msg = "WARNING: atomic_dec_and_test variation before object free at line %s."
coccilib.report.print_report(p1[0], msg % (p2[0].line))
@r4 exists@
identifier a, x, y;
position p1, p2;
identifier fname =~ ".*free.*";
@@
(
atomic_dec_and_test@p1(&(a)->x)
|
atomic_dec_and_lock@p1(&(a)->x, ...)
|
atomic_long_dec_and_lock@p1(&(a)->x, ...)
|
atomic_long_dec_and_test@p1(&(a)->x)
|
atomic64_dec_and_test@p1(&(a)->x)
|
local_dec_and_test@p1(&(a)->x)
)
...
y=a
...
fname@p2(y, ...);
@script:python depends on report@
p1 << r4.p1;
p2 << r4.p2;
@@
msg = "WARNING: atomic_dec_and_test variation before object free at line %s."
coccilib.report.print_report(p1[0], msg % (p2[0].line))
@r2 exists@
identifier a, x;
position p1;
@@
(
atomic_add_unless(&(a)->x,-1,1)@p1
|
atomic_long_add_unless(&(a)->x,-1,1)@p1
|
atomic64_add_unless(&(a)->x,-1,1)@p1
)
@script:python depends on report@
p1 << r2.p1;
@@
msg = "WARNING: atomic_add_unless"
coccilib.report.print_report(p1[0], msg)
@r3 exists@
identifier x;
position p1;
@@
(
x = atomic_add_return@p1(-1, ...);
|
x = atomic_long_add_return@p1(-1, ...);
|
x = atomic64_add_return@p1(-1, ...);
)
@script:python depends on report@
p1 << r3.p1;
@@
msg = "WARNING: x = atomic_add_return(-1, ...)"
coccilib.report.print_report(p1[0], msg)
@@ -0,0 +1,162 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Detect BQ27XXX_DATA structures with identical registers, dm registers or
/// properties.
//# Doesn't unfold macros used in register or property fields.
//# Requires OCaml scripting
///
// Confidence: High
// Copyright: (C) 2017 Julia Lawall, Inria/LIP6,
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Requires: 1.0.7
// Keywords: BQ27XXX_DATA
virtual report
@initialize:ocaml@
@@
let print_report p msg =
let p = List.hd p in
Printf.printf "%s:%d:%d-%d: %s" p.file p.line p.col p.col_end msg
@str depends on report@
type t;
identifier i,i1,i2;
expression e1,e2;
@@
t i[] = {
...,
[e1] = BQ27XXX_DATA(i1,...),
...,
[e2] = BQ27XXX_DATA(i2,...),
...,
};
@script:ocaml tocheck@
i1 << str.i1;
i2 << str.i2;
i1regs; i2regs;
i1dmregs; i2dmregs;
i1props; i2props;
@@
if not(i1 = i2)
then
begin
i1regs := make_ident (i1 ^ "_regs");
i2regs := make_ident (i2 ^ "_regs");
i1dmregs := make_ident (i1 ^ "_dm_regs");
i2dmregs := make_ident (i2 ^ "_dm_regs");
i1props := make_ident (i1 ^ "_props");
i2props := make_ident (i2 ^ "_props")
end
(* ---------------------------------------------------------------- *)
@getregs1@
typedef u8;
identifier tocheck.i1regs;
initializer list i1regs_vals;
position p1;
@@
u8 i1regs@p1[...] = { i1regs_vals, };
@getregs2@
identifier tocheck.i2regs;
initializer list i2regs_vals;
position p2;
@@
u8 i2regs@p2[...] = { i2regs_vals, };
@script:ocaml@
(_,i1regs_vals) << getregs1.i1regs_vals;
(_,i2regs_vals) << getregs2.i2regs_vals;
i1regs << tocheck.i1regs;
i2regs << tocheck.i2regs;
p1 << getregs1.p1;
p2 << getregs2.p2;
@@
if i1regs < i2regs &&
List.sort compare i1regs_vals = List.sort compare i2regs_vals
then
let msg =
Printf.sprintf
"WARNING %s and %s (line %d) are identical\n"
i1regs i2regs (List.hd p2).line in
print_report p1 msg
(* ---------------------------------------------------------------- *)
@getdmregs1@
identifier tocheck.i1dmregs;
initializer list i1dmregs_vals;
position p1;
@@
struct bq27xxx_dm_reg i1dmregs@p1[] = { i1dmregs_vals, };
@getdmregs2@
identifier tocheck.i2dmregs;
initializer list i2dmregs_vals;
position p2;
@@
struct bq27xxx_dm_reg i2dmregs@p2[] = { i2dmregs_vals, };
@script:ocaml@
(_,i1dmregs_vals) << getdmregs1.i1dmregs_vals;
(_,i2dmregs_vals) << getdmregs2.i2dmregs_vals;
i1dmregs << tocheck.i1dmregs;
i2dmregs << tocheck.i2dmregs;
p1 << getdmregs1.p1;
p2 << getdmregs2.p2;
@@
if i1dmregs < i2dmregs &&
List.sort compare i1dmregs_vals = List.sort compare i2dmregs_vals
then
let msg =
Printf.sprintf
"WARNING %s and %s (line %d) are identical\n"
i1dmregs i2dmregs (List.hd p2).line in
print_report p1 msg
(* ---------------------------------------------------------------- *)
@getprops1@
identifier tocheck.i1props;
initializer list[n1] i1props_vals;
position p1;
@@
enum power_supply_property i1props@p1[] = { i1props_vals, };
@getprops2@
identifier tocheck.i2props;
initializer list[n2] i2props_vals;
position p2;
@@
enum power_supply_property i2props@p2[] = { i2props_vals, };
@script:ocaml@
(_,i1props_vals) << getprops1.i1props_vals;
(_,i2props_vals) << getprops2.i2props_vals;
i1props << tocheck.i1props;
i2props << tocheck.i2props;
p1 << getprops1.p1;
p2 << getprops2.p2;
@@
if i1props < i2props &&
List.sort compare i1props_vals = List.sort compare i2props_vals
then
let msg =
Printf.sprintf
"WARNING %s and %s (line %d) are identical\n"
i1props i2props (List.hd p2).line in
print_report p1 msg
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0
/// Make sure calls to d_find_alias() have a corresponding call to dput().
//
// Keywords: d_find_alias, dput
//
// Confidence: Moderate
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --include-headers
virtual context
virtual org
virtual patch
virtual report
@r exists@
local idexpression struct dentry *dent;
expression E, E1;
statement S1, S2;
position p1, p2;
@@
(
if (!(dent@p1 = d_find_alias(...))) S1
|
dent@p1 = d_find_alias(...)
)
<...when != dput(dent)
when != if (...) { <+... dput(dent) ...+> }
when != true !dent || ...
when != dent = E
when != E = dent
if (!dent || ...) S2
...>
(
return <+...dent...+>;
|
return @p2 ...;
|
dent@p2 = E1;
|
E1 = dent;
)
@depends on context@
local idexpression struct dentry *r.dent;
position r.p1,r.p2;
@@
* dent@p1 = ...
...
(
* return@p2 ...;
|
* dent@p2
)
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("Missing call to dput()",p1)
cocci.print_secs("",p2)
@depends on patch@
local idexpression struct dentry *r.dent;
position r.p2;
@@
(
+ dput(dent);
return @p2 ...;
|
+ dput(dent);
dent@p2 = ...;
)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "Missing call to dput() at line %s."
coccilib.report.print_report(p1[0], msg % (p2[0].line))
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// From Documentation/filesystems/sysfs.rst:
/// show() should only use sysfs_emit() or sysfs_emit_at() when formatting
/// the value to be returned to user space.
///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
//
virtual report
virtual org
virtual context
virtual patch
@r depends on !patch@
identifier show, dev, attr, buf;
position p;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
* return snprintf@p(...);
...>
}
@rp depends on patch@
identifier show, dev, attr, buf;
expression BUF, SZ, FORMAT;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
return
- snprintf(BUF, SZ, FORMAT
+ sysfs_emit(BUF, FORMAT
,...);
...>
}
@script: python depends on report@
p << r.p;
@@
coccilib.report.print_report(p[0], "WARNING: please use sysfs_emit or sysfs_emit_at")
@script: python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING: please use sysfs_emit or sysfs_emit_at")
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...))
///
// Confidence: High
// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2009, 2010 Julia Lawall, DIKU.
// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options:
//
// Keywords: ERR_PTR, PTR_ERR, ERR_CAST
// Version min: 2.6.25
//
virtual context
virtual patch
virtual org
virtual report
@ depends on context && !patch && !org && !report@
expression x;
@@
* ERR_PTR(PTR_ERR(x))
@ depends on !context && patch && !org && !report @
expression x;
@@
- ERR_PTR(PTR_ERR(x))
+ ERR_CAST(x)
@r depends on !context && !patch && (org || report)@
expression x;
position p;
@@
ERR_PTR@p(PTR_ERR(x))
@script:python depends on org@
p << r.p;
x << r.x;
@@
msg="WARNING ERR_CAST can be used with %s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r.p;
x << r.x;
@@
msg="WARNING: ERR_CAST can be used with %s" % (x)
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,228 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Check that kvmalloc'ed memory is freed by kfree functions,
/// vmalloc'ed by vfree functions and kvmalloc'ed by kvfree
/// functions.
///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
//
virtual patch
virtual report
virtual org
virtual context
@alloc@
expression E, E1;
position kok, vok;
@@
(
if (...) {
...
E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|
kmalloc_node\|kzalloc_node\|kmalloc_array\|
kmalloc_array_node\|kcalloc_node\)(...)@kok
...
} else {
...
E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
vzalloc_node\|vmalloc_exec\|vmalloc_32\|
vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
__vmalloc_node\)(...)@vok
...
}
|
E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(...)@kok
... when != E = E1
when any
if (E == NULL) {
...
E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
vzalloc_node\|vmalloc_exec\|vmalloc_32\|
vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
__vmalloc_node\)(...)@vok
...
}
)
@free@
expression E;
position fok;
@@
E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
kvmalloc_array\)(...)
...
kvfree(E)@fok
@vfree depends on !patch@
expression E;
position a != alloc.kok;
position f != free.fok;
@@
* E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
* kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
* kcalloc_node\)(...)@a
... when != if (...) { ... E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...); ... }
when != is_vmalloc_addr(E)
when any
* \(vfree\|vfree_atomic\|kvfree\)(E)@f
@depends on patch exists@
expression E;
position a != alloc.kok;
position f != free.fok;
@@
E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
kcalloc_node\)(...)@a
... when != if (...) { ... E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...); ... }
when != is_vmalloc_addr(E)
when any
- \(vfree\|vfree_atomic\|kvfree\)(E)@f
+ kfree(E)
@kfree depends on !patch@
expression E;
position a != alloc.vok;
position f != free.fok;
@@
* E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
* vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
* __vmalloc_node_range\|__vmalloc_node\)(...)@a
... when != is_vmalloc_addr(E)
when any
* \(kfree\|kfree_sensitive\|kvfree\)(E)@f
@depends on patch exists@
expression E;
position a != alloc.vok;
position f != free.fok;
@@
E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
__vmalloc_node_range\|__vmalloc_node\)(...)@a
... when != is_vmalloc_addr(E)
when any
- \(kfree\|kvfree\)(E)@f
+ vfree(E)
@kvfree depends on !patch@
expression E;
position a, f;
@@
* E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
* kvmalloc_array\)(...)@a
... when != is_vmalloc_addr(E)
when any
* \(kfree\|kfree_sensitive\|vfree\|vfree_atomic\)(E)@f
@depends on patch exists@
expression E;
@@
E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
kvmalloc_array\)(...)
... when != is_vmalloc_addr(E)
when any
- \(kfree\|vfree\)(E)
+ kvfree(E)
@kvfree_switch depends on !patch@
expression alloc.E;
position f;
@@
... when != is_vmalloc_addr(E)
when any
* \(kfree\|kfree_sensitive\|vfree\|vfree_atomic\)(E)@f
@depends on patch exists@
expression alloc.E;
position f;
@@
... when != is_vmalloc_addr(E)
when any
(
- \(kfree\|vfree\)(E)@f
+ kvfree(E)
|
- kfree_sensitive(E)@f
+ kvfree_sensitive(E)
)
@script: python depends on report@
a << vfree.a;
f << vfree.f;
@@
msg = "WARNING kmalloc is used to allocate this memory at line %s" % (a[0].line)
coccilib.report.print_report(f[0], msg)
@script: python depends on org@
a << vfree.a;
f << vfree.f;
@@
msg = "WARNING kmalloc is used to allocate this memory at line %s" % (a[0].line)
coccilib.org.print_todo(f[0], msg)
@script: python depends on report@
a << kfree.a;
f << kfree.f;
@@
msg = "WARNING vmalloc is used to allocate this memory at line %s" % (a[0].line)
coccilib.report.print_report(f[0], msg)
@script: python depends on org@
a << kfree.a;
f << kfree.f;
@@
msg = "WARNING vmalloc is used to allocate this memory at line %s" % (a[0].line)
coccilib.org.print_todo(f[0], msg)
@script: python depends on report@
a << kvfree.a;
f << kvfree.f;
@@
msg = "WARNING kvmalloc is used to allocate this memory at line %s" % (a[0].line)
coccilib.report.print_report(f[0], msg)
@script: python depends on org@
a << kvfree.a;
f << kvfree.f;
@@
msg = "WARNING kvmalloc is used to allocate this memory at line %s" % (a[0].line)
coccilib.org.print_todo(f[0], msg)
@script: python depends on report@
ka << alloc.kok;
va << alloc.vok;
f << kvfree_switch.f;
@@
msg = "WARNING kmalloc (line %s) && vmalloc (line %s) are used to allocate this memory" % (ka[0].line, va[0].line)
coccilib.report.print_report(f[0], msg)
@script: python depends on org@
ka << alloc.kok;
va << alloc.vok;
f << kvfree_switch.f;
@@
msg = "WARNING kmalloc (line %s) && vmalloc (line %s) are used to allocate this memory" % (ka[0].line, va[0].line)
coccilib.org.print_todo(f[0], msg)
@@ -0,0 +1,100 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Use kfree_sensitive, kvfree_sensitive rather than memset or
/// memzero_explicit followed by kfree.
///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
//
// Keywords: kfree_sensitive, kvfree_sensitive
//
virtual context
virtual patch
virtual org
virtual report
@initialize:python@
@@
# kmalloc_oob_in_memset uses memset to explicitly trigger out-of-bounds access
filter = frozenset(['kmalloc_oob_in_memset',
'kfree_sensitive', 'kvfree_sensitive'])
def relevant(p):
return not (filter & {el.current_element for el in p})
@cond@
position ok;
@@
if (...)
\(memset@ok\|memzero_explicit@ok\)(...);
@r depends on !patch forall@
expression E;
position p : script:python() { relevant(p) };
position m != cond.ok;
type T;
@@
(
* memset@m((T)E, 0, ...);
|
* memzero_explicit@m((T)E, ...);
)
... when != E
when strict
* \(kfree\|vfree\|kvfree\)(E)@p;
@rp_memzero depends on patch@
expression E, size;
position p : script:python() { relevant(p) };
position m != cond.ok;
type T;
@@
- memzero_explicit@m((T)E, size);
... when != E
when strict
(
- kfree(E)@p;
+ kfree_sensitive(E);
|
- \(vfree\|kvfree\)(E)@p;
+ kvfree_sensitive(E, size);
)
@rp_memset depends on patch@
expression E, size;
position p : script:python() { relevant(p) };
position m != cond.ok;
type T;
@@
- memset@m((T)E, 0, size);
... when != E
when strict
(
- kfree(E)@p;
+ kfree_sensitive(E);
|
- \(vfree\|kvfree\)(E)@p;
+ kvfree_sensitive(E, size);
)
@script:python depends on report@
p << r.p;
m << r.m;
@@
msg = "WARNING opportunity for kfree_sensitive/kvfree_sensitive (memset at line %s)"
coccilib.report.print_report(p[0], msg % (m[0].line))
@script:python depends on org@
p << r.p;
m << r.m;
@@
msg = "WARNING opportunity for kfree_sensitive/kvfree_sensitive (memset at line %s)"
coccilib.org.print_todo(p[0], msg % (m[0].line))
@@ -0,0 +1,135 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Use kmalloc_obj family of macros for allocations
///
// Confidence: High
// Options: --include-headers-for-types --all-includes --include-headers --keep-comments
virtual patch
@initialize:python@
@@
import sys
def alloc_array(name):
func = "FAILED_RENAME"
if name == "kmalloc_array":
func = "kmalloc_objs"
elif name == "kvmalloc_array":
func = "kvmalloc_objs"
elif name == "kcalloc":
func = "kzalloc_objs"
elif name == "kvcalloc":
func = "kvzalloc_objs"
else:
print(f"Unknown transform for {name}", file=sys.stderr)
return func
// This excludes anything that is assigning to or from integral types or
// string literals. Everything else gets the sizeof() extracted for the
// kmalloc_obj() type/var argument. sizeof(void *) is also excluded because
// it will need case-by-case double-checking to make sure the right type is
// being assigned.
@direct depends on patch && !(file in "tools") && !(file in "samples")@
typedef u8, u16, u32, u64;
typedef __u8, __u16, __u32, __u64;
typedef uint8_t, uint16_t, uint32_t, uint64_t;
typedef uchar, ushort, uint, ulong;
typedef __le16, __le32, __le64;
typedef __be16, __be32, __be64;
typedef wchar_t;
type INTEGRAL = {u8,__u8,uint8_t,char,unsigned char,uchar,wchar_t,
u16,__u16,uint16_t,unsigned short,ushort,
u32,__u32,uint32_t,unsigned int,uint,
u64,__u64,uint64_t,unsigned long,ulong,
__le16,__le32,__le64,__be16,__be32,__be64};
char [] STRING;
INTEGRAL *BYTES;
INTEGRAL **BYTES_PTRS;
type TYPE;
expression VAR;
expression GFP;
expression COUNT;
expression FLEX;
expression E;
identifier ALLOC =~ "^kv?[mz]alloc$";
fresh identifier ALLOC_OBJ = ALLOC ## "_obj";
fresh identifier ALLOC_FLEX = ALLOC ## "_flex";
identifier ALLOC_ARRAY = {kmalloc_array,kvmalloc_array,kcalloc,kvcalloc};
fresh identifier ALLOC_OBJS = script:python(ALLOC_ARRAY) { alloc_array(ALLOC_ARRAY) };
@@
(
- VAR = ALLOC((sizeof(*VAR)), GFP)
+ VAR = ALLOC_OBJ(*VAR, GFP)
|
ALLOC((\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP)
|
BYTES = ALLOC((sizeof(E)), GFP)
|
BYTES = ALLOC((sizeof(TYPE)), GFP)
|
BYTES_PTRS = ALLOC((sizeof(E)), GFP)
|
BYTES_PTRS = ALLOC((sizeof(TYPE)), GFP)
|
ALLOC((sizeof(void *)), GFP)
|
- ALLOC((sizeof(E)), GFP)
+ ALLOC_OBJ(E, GFP)
|
- ALLOC((sizeof(TYPE)), GFP)
+ ALLOC_OBJ(TYPE, GFP)
|
ALLOC_ARRAY(COUNT, (\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP)
|
BYTES = ALLOC_ARRAY(COUNT, (sizeof(E)), GFP)
|
BYTES = ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP)
|
BYTES_PTRS = ALLOC_ARRAY(COUNT, (sizeof(E)), GFP)
|
BYTES_PTRS = ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP)
|
ALLOC_ARRAY((\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), COUNT, GFP)
|
BYTES = ALLOC_ARRAY((sizeof(E)), COUNT, GFP)
|
BYTES = ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP)
|
BYTES_PTRS = ALLOC_ARRAY((sizeof(E)), COUNT, GFP)
|
BYTES_PTRS = ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP)
|
ALLOC_ARRAY(COUNT, (sizeof(void *)), GFP)
|
ALLOC_ARRAY((sizeof(void *)), COUNT, GFP)
|
- ALLOC_ARRAY(COUNT, (sizeof(E)), GFP)
+ ALLOC_OBJS(E, COUNT, GFP)
|
- ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP)
+ ALLOC_OBJS(TYPE, COUNT, GFP)
|
- ALLOC_ARRAY((sizeof(E)), COUNT, GFP)
+ ALLOC_OBJS(E, COUNT, GFP)
|
- ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP)
+ ALLOC_OBJS(TYPE, COUNT, GFP)
|
- ALLOC(struct_size(VAR, FLEX, COUNT), GFP)
+ ALLOC_FLEX(*VAR, FLEX, COUNT, GFP)
|
- ALLOC(struct_size_t(TYPE, FLEX, COUNT), GFP)
+ ALLOC_FLEX(TYPE, FLEX, COUNT, GFP)
)
@drop_gfp_kernel depends on patch && !(file in "tools") && !(file in "samples")@
identifier ALLOC = {kmalloc_obj,kmalloc_objs,kmalloc_flex,
kzalloc_obj,kzalloc_objs,kzalloc_flex,
kvmalloc_obj,kvmalloc_objs,kvmalloc_flex,
kvzalloc_obj,kvzalloc_objs,kvzalloc_flex};
@@
ALLOC(...
- , GFP_KERNEL
)
@@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Use kstrdup rather than duplicating its implementation
///
// Confidence: High
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@depends on patch@
expression from,to;
expression flag,E1,E2;
statement S;
@@
- to = kmalloc(strlen(from) + 1,flag);
+ to = kstrdup(from, flag);
... when != \(from = E1 \| to = E1 \)
if (to==NULL || ...) S
... when != \(from = E2 \| to = E2 \)
- strcpy(to, from);
@depends on patch@
expression x,from,to;
expression flag,E1,E2,E3;
statement S;
@@
- x = strlen(from) + 1;
... when != \( x = E1 \| from = E1 \)
- to = \(kmalloc\|kzalloc\)(x,flag);
+ to = kstrdup(from, flag);
... when != \(x = E2 \| from = E2 \| to = E2 \)
if (to==NULL || ...) S
... when != \(x = E3 \| from = E3 \| to = E3 \)
- memcpy(to, from, x);
// ---------------------------------------------------------------------
@r1 depends on !patch exists@
expression from,to;
expression flag,E1,E2;
statement S;
position p1,p2;
@@
* to = kmalloc@p1(strlen(from) + 1,flag);
... when != \(from = E1 \| to = E1 \)
if (to==NULL || ...) S
... when != \(from = E2 \| to = E2 \)
* strcpy@p2(to, from);
@r2 depends on !patch exists@
expression x,from,to;
expression flag,E1,E2,E3;
statement S;
position p1,p2;
@@
* x = strlen(from) + 1;
... when != \( x = E1 \| from = E1 \)
* to = \(kmalloc@p1\|kzalloc@p1\)(x,flag);
... when != \(x = E2 \| from = E2 \| to = E2 \)
if (to==NULL || ...) S
... when != \(x = E3 \| from = E3 \| to = E3 \)
* memcpy@p2(to, from, x);
@script:python depends on org@
p1 << r1.p1;
p2 << r1.p2;
@@
cocci.print_main("WARNING opportunity for kstrdup",p1)
cocci.print_secs("strcpy",p2)
@script:python depends on org@
p1 << r2.p1;
p2 << r2.p2;
@@
cocci.print_main("WARNING opportunity for kstrdup",p1)
cocci.print_secs("memcpy",p2)
@script:python depends on report@
p1 << r1.p1;
p2 << r1.p2;
@@
msg = "WARNING opportunity for kstrdup (strcpy on line %s)" % (p2[0].line)
coccilib.report.print_report(p1[0], msg)
@script:python depends on report@
p1 << r2.p1;
p2 << r2.p2;
@@
msg = "WARNING opportunity for kstrdup (memcpy on line %s)" % (p2[0].line)
coccilib.report.print_report(p1[0], msg)
@@ -0,0 +1,256 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Find if/else condition with kmalloc/vmalloc calls.
/// Suggest to use kvmalloc instead. Same for kvfree.
///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
//
virtual patch
virtual report
virtual org
virtual context
@initialize:python@
@@
filter = frozenset(['kvfree'])
def relevant(p):
return not (filter & {el.current_element for el in p})
@kvmalloc depends on !patch@
expression E, E1, size;
identifier flags;
binary operator cmp = {<=, <, ==, >, >=};
identifier x;
type T;
position p;
@@
(
* if (size cmp E1 || ...)@p {
...
* E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
* (..., size, \(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), ...)
...
} else {
...
* E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
...
}
|
* E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
* (..., size, \(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), ...)
... when != E = E1
when != size = E1
when any
* if (E == NULL)@p {
...
* E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
...
}
|
* T x = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
* (..., size, \(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), ...);
... when != x = E1
when != size = E1
when any
* if (x == NULL)@p {
...
* x = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
...
}
)
@kvfree depends on !patch@
expression E;
position p : script:python() { relevant(p) };
@@
* if (is_vmalloc_addr(E))@p {
...
* vfree(E)
...
} else {
... when != krealloc(E, ...)
when any
* \(kfree\|kfree_sensitive\)(E)
...
}
@depends on patch@
expression E, E1, size, node;
binary operator cmp = {<=, <, ==, >, >=};
identifier flags, x;
type T;
@@
(
- if (size cmp E1)
- E = kmalloc(size, flags);
- else
- E = vmalloc(size);
+ E = kvmalloc(size, flags);
|
- if (size cmp E1)
- E = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
- else
- E = vmalloc(size);
+ E = kvmalloc(size, GFP_KERNEL);
|
- E = kmalloc(size, flags | __GFP_NOWARN);
- if (E == NULL)
- E = vmalloc(size);
+ E = kvmalloc(size, flags);
|
- E = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
- if (E == NULL)
- E = vmalloc(size);
+ E = kvmalloc(size, GFP_KERNEL);
|
- T x = kmalloc(size, flags | __GFP_NOWARN);
- if (x == NULL)
- x = vmalloc(size);
+ T x = kvmalloc(size, flags);
|
- T x = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
- if (x == NULL)
- x = vmalloc(size);
+ T x = kvmalloc(size, GFP_KERNEL);
|
- if (size cmp E1)
- E = kzalloc(size, flags);
- else
- E = vzalloc(size);
+ E = kvzalloc(size, flags);
|
- if (size cmp E1)
- E = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
- else
- E = vzalloc(size);
+ E = kvzalloc(size, GFP_KERNEL);
|
- E = kzalloc(size, flags | __GFP_NOWARN);
- if (E == NULL)
- E = vzalloc(size);
+ E = kvzalloc(size, flags);
|
- E = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
- if (E == NULL)
- E = vzalloc(size);
+ E = kvzalloc(size, GFP_KERNEL);
|
- T x = kzalloc(size, flags | __GFP_NOWARN);
- if (x == NULL)
- x = vzalloc(size);
+ T x = kvzalloc(size, flags);
|
- T x = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
- if (x == NULL)
- x = vzalloc(size);
+ T x = kvzalloc(size, GFP_KERNEL);
|
- if (size cmp E1)
- E = kmalloc_node(size, flags, node);
- else
- E = vmalloc_node(size, node);
+ E = kvmalloc_node(size, flags, node);
|
- if (size cmp E1)
- E = kmalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
- else
- E = vmalloc_node(size, node);
+ E = kvmalloc_node(size, GFP_KERNEL, node);
|
- E = kmalloc_node(size, flags | __GFP_NOWARN, node);
- if (E == NULL)
- E = vmalloc_node(size, node);
+ E = kvmalloc_node(size, flags, node);
|
- E = kmalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
- if (E == NULL)
- E = vmalloc_node(size, node);
+ E = kvmalloc_node(size, GFP_KERNEL, node);
|
- T x = kmalloc_node(size, flags | __GFP_NOWARN, node);
- if (x == NULL)
- x = vmalloc_node(size, node);
+ T x = kvmalloc_node(size, flags, node);
|
- T x = kmalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
- if (x == NULL)
- x = vmalloc_node(size, node);
+ T x = kvmalloc_node(size, GFP_KERNEL, node);
|
- if (size cmp E1)
- E = kvzalloc_node(size, flags, node);
- else
- E = vzalloc_node(size, node);
+ E = kvzalloc_node(size, flags, node);
|
- if (size cmp E1)
- E = kvzalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
- else
- E = vzalloc_node(size, node);
+ E = kvzalloc_node(size, GFP_KERNEL, node);
|
- E = kvzalloc_node(size, flags | __GFP_NOWARN, node);
- if (E == NULL)
- E = vzalloc_node(size, node);
+ E = kvzalloc_node(size, flags, node);
|
- E = kvzalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
- if (E == NULL)
- E = vzalloc_node(size, node);
+ E = kvzalloc_node(size, GFP_KERNEL, node);
|
- T x = kvzalloc_node(size, flags | __GFP_NOWARN, node);
- if (x == NULL)
- x = vzalloc_node(size, node);
+ T x = kvzalloc_node(size, flags, node);
|
- T x = kvzalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
- if (x == NULL)
- x = vzalloc_node(size, node);
+ T x = kvzalloc_node(size, GFP_KERNEL, node);
)
@depends on patch@
expression E;
position p : script:python() { relevant(p) };
@@
- if (is_vmalloc_addr(E))@p
- vfree(E);
- else
- kfree(E);
+ kvfree(E);
@script: python depends on report@
p << kvmalloc.p;
@@
coccilib.report.print_report(p[0], "WARNING opportunity for kvmalloc")
@script: python depends on org@
p << kvmalloc.p;
@@
coccilib.org.print_todo(p[0], "WARNING opportunity for kvmalloc")
@script: python depends on report@
p << kvfree.p;
@@
coccilib.report.print_report(p[0], "WARNING opportunity for kvfree")
@script: python depends on org@
p << kvfree.p;
@@
coccilib.org.print_todo(p[0], "WARNING opportunity for kvfree")
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Use kmemdup rather than duplicating its implementation
///
// Confidence: High
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@r1@
expression from,to;
expression flag;
position p;
@@
to = \(kmalloc@p\|kzalloc@p\)(strlen(from) + 1,flag);
@r2@
expression x,from,to;
expression flag,E1;
position p;
@@
x = strlen(from) + 1;
... when != \( x = E1 \| from = E1 \)
to = \(kmalloc@p\|kzalloc@p\)(x,flag);
@depends on patch@
expression from,to,size,flag;
position p != {r1.p,r2.p};
statement S;
@@
- to = \(kmalloc@p\|kzalloc@p\)(size,flag);
+ to = kmemdup(from,size,flag);
if (to==NULL || ...) S
- memcpy(to, from, size);
@r depends on !patch@
expression from,to,size,flag;
position p != {r1.p,r2.p};
statement S;
@@
* to = \(kmalloc@p\|kzalloc@p\)(size,flag);
if (to==NULL || ...) S
* memcpy(to, from, size);
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING opportunity for kmemdup")
@script:python depends on report@
p << r.p;
@@
coccilib.report.print_report(p[0], "WARNING opportunity for kmemdup")
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Use memdup_user rather than duplicating its implementation
/// This is a little bit restricted to reduce false positives
///
// Confidence: High
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@initialize:python@
@@
filter = frozenset(['memdup_user', 'vmemdup_user'])
def relevant(p):
return not (filter & {el.current_element for el in p})
@depends on patch@
expression from,to,size;
identifier l1,l2;
position p : script:python() { relevant(p) };
@@
- to = \(kmalloc@p\|kzalloc@p\)
- (size,\(GFP_KERNEL\|GFP_USER\|
- \(GFP_KERNEL\|GFP_USER\)|__GFP_NOWARN\));
+ to = memdup_user(from,size);
if (
- to==NULL
+ IS_ERR(to)
|| ...) {
<+... when != goto l1;
- -ENOMEM
+ PTR_ERR(to)
...+>
}
- if (copy_from_user(to, from, size) != 0) {
- <+... when != goto l2;
- -EFAULT
- ...+>
- }
@depends on patch@
expression from,to,size;
identifier l1,l2;
position p : script:python() { relevant(p) };
@@
- to = \(kvmalloc@p\|kvzalloc@p\)(size,\(GFP_KERNEL\|GFP_USER\));
+ to = vmemdup_user(from,size);
if (
- to==NULL
+ IS_ERR(to)
|| ...) {
<+... when != goto l1;
- -ENOMEM
+ PTR_ERR(to)
...+>
}
- if (copy_from_user(to, from, size) != 0) {
- <+... when != goto l2;
- -EFAULT
- ...+>
- }
@r depends on !patch@
expression from,to,size;
position p : script:python() { relevant(p) };
statement S1,S2;
@@
* to = \(kmalloc@p\|kzalloc@p\)
(size,\(GFP_KERNEL\|GFP_USER\|
\(GFP_KERNEL\|GFP_USER\)|__GFP_NOWARN\));
if (to==NULL || ...) S1
if (copy_from_user(to, from, size) != 0)
S2
@rv depends on !patch@
expression from,to,size;
position p : script:python() { relevant(p) };
statement S1,S2;
@@
* to = \(kvmalloc@p\|kvzalloc@p\)(size,\(GFP_KERNEL\|GFP_USER\));
if (to==NULL || ...) S1
if (copy_from_user(to, from, size) != 0)
S2
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING opportunity for memdup_user")
@script:python depends on report@
p << r.p;
@@
coccilib.report.print_report(p[0], "WARNING opportunity for memdup_user")
@script:python depends on org@
p << rv.p;
@@
coccilib.org.print_todo(p[0], "WARNING opportunity for vmemdup_user")
@script:python depends on report@
p << rv.p;
@@
coccilib.report.print_report(p[0], "WARNING opportunity for vmemdup_user")
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0
/// Remove dev_err() messages after platform_get_irq*() failures
//
// Confidence: Medium
// Options: --include-headers
virtual patch
virtual context
virtual org
virtual report
@depends on context@
expression ret;
struct platform_device *E;
@@
ret =
(
platform_get_irq
|
platform_get_irq_byname
)(E, ...);
if ( \( ret < 0 \| ret <= 0 \) )
{
(
if (ret != -EPROBE_DEFER)
{ ...
*dev_err(...);
... }
|
...
*dev_err(...);
)
...
}
@depends on patch@
expression ret;
struct platform_device *E;
@@
ret =
(
platform_get_irq
|
platform_get_irq_byname
)(E, ...);
if ( \( ret < 0 \| ret <= 0 \) )
{
(
-if (ret != -EPROBE_DEFER)
-{ ...
-dev_err(...);
-... }
|
...
-dev_err(...);
)
...
}
@r depends on org || report@
position p1;
expression ret;
struct platform_device *E;
@@
ret =
(
platform_get_irq
|
platform_get_irq_byname
)(E, ...);
if ( \( ret < 0 \| ret <= 0 \) )
{
(
if (ret != -EPROBE_DEFER)
{ ...
dev_err@p1(...);
... }
|
...
dev_err@p1(...);
)
...
}
@script:python depends on org@
p1 << r.p1;
@@
cocci.print_main(p1)
@script:python depends on report@
p1 << r.p1;
@@
msg = "line %s is redundant because platform_get_irq() already prints an error" % (p1[0].line)
coccilib.report.print_report(p1[0],msg)
@@ -0,0 +1,189 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Remove .owner field if calls are used which set it automatically
///
// Confidence: High
// Copyright: (C) 2014 Wolfram Sang.
virtual patch
virtual context
virtual org
virtual report
@match1@
declarer name builtin_i2c_driver;
declarer name builtin_platform_driver;
declarer name builtin_platform_driver_probe;
declarer name module_i2c_driver;
declarer name module_platform_driver;
declarer name module_platform_driver_probe;
identifier __driver;
@@
(
builtin_i2c_driver(__driver);
|
builtin_platform_driver(__driver);
|
builtin_platform_driver_probe(__driver, ...);
|
module_i2c_driver(__driver);
|
module_platform_driver(__driver);
|
module_platform_driver_probe(__driver, ...);
)
@fix1 depends on match1 && patch && !context && !org && !report@
identifier match1.__driver;
@@
static struct platform_driver __driver = {
.driver = {
- .owner = THIS_MODULE,
}
};
@fix1_i2c depends on match1 && patch && !context && !org && !report@
identifier match1.__driver;
@@
static struct i2c_driver __driver = {
.driver = {
- .owner = THIS_MODULE,
}
};
@match2@
identifier __driver;
@@
(
platform_driver_register(&__driver)
|
platform_driver_probe(&__driver, ...)
|
platform_create_bundle(&__driver, ...)
|
i2c_add_driver(&__driver)
)
@fix2 depends on match2 && patch && !context && !org && !report@
identifier match2.__driver;
@@
static struct platform_driver __driver = {
.driver = {
- .owner = THIS_MODULE,
}
};
@fix2_i2c depends on match2 && patch && !context && !org && !report@
identifier match2.__driver;
@@
static struct i2c_driver __driver = {
.driver = {
- .owner = THIS_MODULE,
}
};
// ----------------------------------------------------------------------------
@fix1_context depends on match1 && !patch && (context || org || report)@
identifier match1.__driver;
position j0;
@@
static struct platform_driver __driver = {
.driver = {
* .owner@j0 = THIS_MODULE,
}
};
@fix1_i2c_context depends on match1 && !patch && (context || org || report)@
identifier match1.__driver;
position j0;
@@
static struct i2c_driver __driver = {
.driver = {
* .owner@j0 = THIS_MODULE,
}
};
@fix2_context depends on match2 && !patch && (context || org || report)@
identifier match2.__driver;
position j0;
@@
static struct platform_driver __driver = {
.driver = {
* .owner@j0 = THIS_MODULE,
}
};
@fix2_i2c_context depends on match2 && !patch && (context || org || report)@
identifier match2.__driver;
position j0;
@@
static struct i2c_driver __driver = {
.driver = {
* .owner@j0 = THIS_MODULE,
}
};
// ----------------------------------------------------------------------------
@script:python fix1_org depends on org@
j0 << fix1_context.j0;
@@
msg = "No need to set .owner here. The core will do it."
coccilib.org.print_todo(j0[0], msg)
@script:python fix1_i2c_org depends on org@
j0 << fix1_i2c_context.j0;
@@
msg = "No need to set .owner here. The core will do it."
coccilib.org.print_todo(j0[0], msg)
@script:python fix2_org depends on org@
j0 << fix2_context.j0;
@@
msg = "No need to set .owner here. The core will do it."
coccilib.org.print_todo(j0[0], msg)
@script:python fix2_i2c_org depends on org@
j0 << fix2_i2c_context.j0;
@@
msg = "No need to set .owner here. The core will do it."
coccilib.org.print_todo(j0[0], msg)
// ----------------------------------------------------------------------------
@script:python fix1_report depends on report@
j0 << fix1_context.j0;
@@
msg = "No need to set .owner here. The core will do it."
coccilib.report.print_report(j0[0], msg)
@script:python fix1_i2c_report depends on report@
j0 << fix1_i2c_context.j0;
@@
msg = "No need to set .owner here. The core will do it."
coccilib.report.print_report(j0[0], msg)
@script:python fix2_report depends on report@
j0 << fix2_context.j0;
@@
msg = "No need to set .owner here. The core will do it."
coccilib.report.print_report(j0[0], msg)
@script:python fix2_i2c_report depends on report@
j0 << fix2_i2c_context.j0;
@@
msg = "No need to set .owner here. The core will do it."
coccilib.report.print_report(j0[0], msg)
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Make sure pm_runtime_* calls do not unnecessarily use IS_ERR_VALUE
///
// Keywords: pm_runtime
// Confidence: Medium
// Copyright (C) 2013 Texas Instruments Incorporated -
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --include-headers
virtual patch
virtual context
virtual org
virtual report
//----------------------------------------------------------
// Detection
//----------------------------------------------------------
@runtime_bad_err_handle exists@
expression ret;
position p;
@@
(
ret@p = \(pm_runtime_idle\|
pm_runtime_suspend\|
pm_runtime_autosuspend\|
pm_runtime_resume\|
pm_request_idle\|
pm_request_resume\|
pm_request_autosuspend\|
pm_runtime_get\|
pm_runtime_get_sync\|
pm_runtime_put\|
pm_runtime_put_autosuspend\|
pm_runtime_put_sync\|
pm_runtime_put_sync_suspend\|
pm_runtime_put_sync_autosuspend\|
pm_runtime_set_active\|
pm_schedule_suspend\|
pm_generic_runtime_suspend\|
pm_generic_runtime_resume\)(...);
...
IS_ERR_VALUE(ret)
...
)
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@depends on context@
identifier pm_runtime_api;
expression ret;
position runtime_bad_err_handle.p;
@@
(
ret@p = pm_runtime_api(...);
...
* IS_ERR_VALUE(ret)
...
)
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@depends on patch@
identifier pm_runtime_api;
expression ret;
position runtime_bad_err_handle.p;
@@
(
ret@p = pm_runtime_api(...);
...
- IS_ERR_VALUE(ret)
+ ret < 0
...
)
//----------------------------------------------------------
// For org and report mode
//----------------------------------------------------------
@r depends on (org || report) exists@
position p1, p2;
identifier pm_runtime_api;
expression ret;
position runtime_bad_err_handle.p;
@@
(
ret@p = pm_runtime_api@p1(...);
...
IS_ERR_VALUE@p2(ret)
...
)
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
pm_runtime_api << r.pm_runtime_api;
@@
cocci.print_main(pm_runtime_api,p1)
cocci.print_secs("IS_ERR_VALUE",p2)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
pm_runtime_api << r.pm_runtime_api;
@@
msg = "%s returns < 0 as error. Unnecessary IS_ERR_VALUE at line %s" % (pm_runtime_api, p2[0].line)
coccilib.report.print_report(p1[0],msg)
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Use resource_size function on resource object
/// instead of explicit computation.
///
// Confidence: High
// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2009, 2010 Julia Lawall, DIKU.
// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options:
//
// Keywords: resource_size
// Version min: 2.6.27 resource_size
//
virtual context
virtual patch
virtual org
virtual report
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@r_context depends on context && !patch && !org@
struct resource *res;
@@
* (res->end - res->start) + 1
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@r_patch depends on !context && patch && !org@
struct resource *res;
@@
- (res->end - res->start) + 1
+ resource_size(res)
//----------------------------------------------------------
// For org mode
//----------------------------------------------------------
@r_org depends on !context && !patch && (org || report)@
struct resource *res;
position p;
@@
(res->end@p - res->start) + 1
@rbad_org depends on !context && !patch && (org || report)@
struct resource *res;
position p != r_org.p;
@@
res->end@p - res->start
@script:python depends on org@
p << r_org.p;
x << r_org.res;
@@
msg="ERROR with %s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << r_org.p;
x << r_org.res;
@@
msg="ERROR: Missing resource_size with %s" % (x)
coccilib.report.print_report(p[0], msg)
@script:python depends on org@
p << rbad_org.p;
x << rbad_org.res;
@@
msg="WARNING with %s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@script:python depends on report@
p << rbad_org.p;
x << rbad_org.res;
@@
msg="WARNING: Suspicious code. resource_size is maybe missing with %s" % (x)
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0
/// Remove an open coded simple_open() function
/// and replace file operations references to the function
/// with simple_open() instead.
///
// Confidence: High
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual report
@ open depends on patch @
identifier open_f != simple_open;
identifier i, f;
@@
-int open_f(struct inode *i, struct file *f)
-{
(
-if (i->i_private)
-f->private_data = i->i_private;
|
-f->private_data = i->i_private;
)
-return 0;
-}
@ has_open depends on open @
identifier fops;
identifier open.open_f;
@@
struct file_operations fops = {
...,
-.open = open_f,
+.open = simple_open,
...
};
@ openr depends on report @
identifier open_f != simple_open;
identifier i, f;
position p;
@@
int open_f@p(struct inode *i, struct file *f)
{
(
if (i->i_private)
f->private_data = i->i_private;
|
f->private_data = i->i_private;
)
return 0;
}
@ has_openr depends on openr @
identifier fops;
identifier openr.open_f;
position p;
@@
struct file_operations fops = {
...,
.open = open_f@p,
...
};
@script:python@
pf << openr.p;
ps << has_openr.p;
@@
coccilib.report.print_report(pf[0],"WARNING opportunity for simple_open, see also structure on line %s"%(ps[0].line))
@@ -0,0 +1,369 @@
// SPDX-License-Identifier: GPL-2.0
// Author: Kirill Smelkov (kirr@nexedi.com)
//
// Search for stream-like files that are using nonseekable_open and convert
// them to stream_open. A stream-like file is a file that does not use ppos in
// its read and write. Rationale for the conversion is to avoid deadlock in
// between read and write.
virtual report
virtual patch
virtual explain // explain decisions in the patch (SPFLAGS="-D explain")
// stream-like reader & writer - ones that do not depend on f_pos.
@ stream_reader @
identifier readstream, ppos;
identifier f, buf, len;
type loff_t;
@@
ssize_t readstream(struct file *f, char *buf, size_t len, loff_t *ppos)
{
... when != ppos
}
@ stream_writer @
identifier writestream, ppos;
identifier f, buf, len;
type loff_t;
@@
ssize_t writestream(struct file *f, const char *buf, size_t len, loff_t *ppos)
{
... when != ppos
}
// a function that blocks
@ blocks @
identifier block_f;
identifier wait =~ "^wait_.*";
@@
block_f(...) {
... when exists
wait(...)
... when exists
}
// stream_reader that can block inside.
//
// XXX wait_* can be called not directly from current function (e.g. func -> f -> g -> wait())
// XXX currently reader_blocks supports only direct and 1-level indirect cases.
@ reader_blocks_direct @
identifier stream_reader.readstream;
identifier wait =~ "^wait_.*";
@@
readstream(...)
{
... when exists
wait(...)
... when exists
}
@ reader_blocks_1 @
identifier stream_reader.readstream;
identifier blocks.block_f;
@@
readstream(...)
{
... when exists
block_f(...)
... when exists
}
@ reader_blocks depends on reader_blocks_direct || reader_blocks_1 @
identifier stream_reader.readstream;
@@
readstream(...) {
...
}
// file_operations + whether they have _any_ .read, .write, .llseek ... at all.
//
// XXX add support for file_operations xxx[N] = ... (sound/core/pcm_native.c)
@ fops0 @
identifier fops;
@@
struct file_operations fops = {
...
};
@ has_read @
identifier fops0.fops;
identifier read_f;
@@
struct file_operations fops = {
.read = read_f,
};
@ has_read_iter @
identifier fops0.fops;
identifier read_iter_f;
@@
struct file_operations fops = {
.read_iter = read_iter_f,
};
@ has_write @
identifier fops0.fops;
identifier write_f;
@@
struct file_operations fops = {
.write = write_f,
};
@ has_write_iter @
identifier fops0.fops;
identifier write_iter_f;
@@
struct file_operations fops = {
.write_iter = write_iter_f,
};
@ has_llseek @
identifier fops0.fops;
identifier llseek_f;
@@
struct file_operations fops = {
.llseek = llseek_f,
};
@ has_no_llseek @
identifier fops0.fops;
@@
struct file_operations fops = {
};
@ has_noop_llseek @
identifier fops0.fops;
@@
struct file_operations fops = {
.llseek = noop_llseek,
};
@ has_mmap @
identifier fops0.fops;
identifier mmap_f;
@@
struct file_operations fops = {
.mmap = mmap_f,
};
@ has_copy_file_range @
identifier fops0.fops;
identifier copy_file_range_f;
@@
struct file_operations fops = {
.copy_file_range = copy_file_range_f,
};
@ has_remap_file_range @
identifier fops0.fops;
identifier remap_file_range_f;
@@
struct file_operations fops = {
.remap_file_range = remap_file_range_f,
};
@ has_splice_read @
identifier fops0.fops;
identifier splice_read_f;
@@
struct file_operations fops = {
.splice_read = splice_read_f,
};
@ has_splice_write @
identifier fops0.fops;
identifier splice_write_f;
@@
struct file_operations fops = {
.splice_write = splice_write_f,
};
// file_operations that is candidate for stream_open conversion - it does not
// use mmap and other methods that assume @offset access to file.
//
// XXX for simplicity require no .{read/write}_iter and no .splice_{read/write} for now.
// XXX maybe_steam.fops cannot be used in other rules - it gives "bad rule maybe_stream or bad variable fops".
@ maybe_stream depends on (!has_llseek || has_no_llseek || has_noop_llseek) && !has_mmap && !has_copy_file_range && !has_remap_file_range && !has_read_iter && !has_write_iter && !has_splice_read && !has_splice_write @
identifier fops0.fops;
@@
struct file_operations fops = {
};
// ---- conversions ----
// XXX .open = nonseekable_open -> .open = stream_open
// XXX .open = func -> openfunc -> nonseekable_open
// read & write
//
// if both are used in the same file_operations together with an opener -
// under that conditions we can use stream_open instead of nonseekable_open.
@ fops_rw depends on maybe_stream @
identifier fops0.fops, openfunc;
identifier stream_reader.readstream;
identifier stream_writer.writestream;
@@
struct file_operations fops = {
.open = openfunc,
.read = readstream,
.write = writestream,
};
@ report_rw depends on report @
identifier fops_rw.openfunc;
position p1;
@@
openfunc(...) {
<...
nonseekable_open@p1
...>
}
@ script:python depends on report && reader_blocks @
fops << fops0.fops;
p << report_rw.p1;
@@
coccilib.report.print_report(p[0],
"ERROR: %s: .read() can deadlock .write(); change nonseekable_open -> stream_open to fix." % (fops,))
@ script:python depends on report && !reader_blocks @
fops << fops0.fops;
p << report_rw.p1;
@@
coccilib.report.print_report(p[0],
"WARNING: %s: .read() and .write() have stream semantic; safe to change nonseekable_open -> stream_open." % (fops,))
@ explain_rw_deadlocked depends on explain && reader_blocks @
identifier fops_rw.openfunc;
@@
openfunc(...) {
<...
- nonseekable_open
+ nonseekable_open /* read & write (was deadlock) */
...>
}
@ explain_rw_nodeadlock depends on explain && !reader_blocks @
identifier fops_rw.openfunc;
@@
openfunc(...) {
<...
- nonseekable_open
+ nonseekable_open /* read & write (no direct deadlock) */
...>
}
@ patch_rw depends on patch @
identifier fops_rw.openfunc;
@@
openfunc(...) {
<...
- nonseekable_open
+ stream_open
...>
}
// read, but not write
@ fops_r depends on maybe_stream && !has_write @
identifier fops0.fops, openfunc;
identifier stream_reader.readstream;
@@
struct file_operations fops = {
.open = openfunc,
.read = readstream,
};
@ report_r depends on report @
identifier fops_r.openfunc;
position p1;
@@
openfunc(...) {
<...
nonseekable_open@p1
...>
}
@ script:python depends on report @
fops << fops0.fops;
p << report_r.p1;
@@
coccilib.report.print_report(p[0],
"WARNING: %s: .read() has stream semantic; safe to change nonseekable_open -> stream_open." % (fops,))
@ explain_r depends on explain @
identifier fops_r.openfunc;
@@
openfunc(...) {
<...
- nonseekable_open
+ nonseekable_open /* read only */
...>
}
@ patch_r depends on patch @
identifier fops_r.openfunc;
@@
openfunc(...) {
<...
- nonseekable_open
+ stream_open
...>
}
// write, but not read
@ fops_w depends on maybe_stream && !has_read @
identifier fops0.fops, openfunc;
identifier stream_writer.writestream;
@@
struct file_operations fops = {
.open = openfunc,
.write = writestream,
};
@ report_w depends on report @
identifier fops_w.openfunc;
position p1;
@@
openfunc(...) {
<...
nonseekable_open@p1
...>
}
@ script:python depends on report @
fops << fops0.fops;
p << report_w.p1;
@@
coccilib.report.print_report(p[0],
"WARNING: %s: .write() has stream semantic; safe to change nonseekable_open -> stream_open." % (fops,))
@ explain_w depends on explain @
identifier fops_w.openfunc;
@@
openfunc(...) {
<...
- nonseekable_open
+ nonseekable_open /* write only */
...>
}
@ patch_w depends on patch @
identifier fops_w.openfunc;
@@
openfunc(...) {
<...
- nonseekable_open
+ stream_open
...>
}
// no read, no write - don't change anything
@@ -0,0 +1,302 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find places to use string_choices.h's various helpers.
//
// Confidence: Medium
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual report
@str_plural depends on patch@
expression E;
@@
(
- ((E == 1) ? "" : "s")
+ str_plural(E)
|
- ((E > 1) ? "s" : "")
+ str_plural(E)
)
@str_plural_r depends on !patch@
expression E;
position P;
@@
(
* (E@P == 1) ? "" : "s"
|
* (E@P > 1) ? "s" : ""
)
@script:python depends on report@
p << str_plural_r.P;
e << str_plural_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_plural(%s)" % e)
@str_up_down depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "up" : "down")
+ str_up_down(E)
@str_up_down_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "up" : "down"
@script:python depends on report@
p << str_up_down_r.P;
e << str_up_down_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_up_down(%s)" % e)
@str_down_up depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "down" : "up")
+ str_down_up(E)
@str_down_up_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "down" : "up"
@script:python depends on report@
p << str_down_up_r.P;
e << str_down_up_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_down_up(%s)" % e)
@str_true_false depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "true" : "false")
+ str_true_false(E)
@str_true_false_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "true" : "false"
@script:python depends on report@
p << str_true_false_r.P;
e << str_true_false_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_true_false(%s)" % e)
@str_false_true depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "false" : "true")
+ str_false_true(E)
@str_false_true_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "false" : "true"
@script:python depends on report@
p << str_false_true_r.P;
e << str_false_true_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_false_true(%s)" % e)
@str_hi_lo depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "hi" : "lo")
+ str_hi_lo(E)
@str_hi_lo_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "hi" : "lo"
@script:python depends on report@
p << str_hi_lo_r.P;
e << str_hi_lo_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_hi_lo(%s)" % e)
@str_high_low depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "high" : "low")
+ str_high_low(E)
@str_high_low_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "high" : "low"
@script:python depends on report@
p << str_high_low_r.P;
e << str_high_low_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_high_low(%s)" % e)
@str_lo_hi depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "lo" : "hi")
+ str_lo_hi(E)
@str_lo_hi_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "lo" : "hi"
@script:python depends on report@
p << str_lo_hi_r.P;
e << str_lo_hi_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_lo_hi(%s)" % e)
@str_low_high depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "low" : "high")
+ str_low_high(E)
@str_low_high_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "low" : "high"
@script:python depends on report@
p << str_low_high_r.P;
e << str_low_high_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_low_high(%s)" % e)
@str_enable_disable depends on patch@
expression E;
@@
- ((E) ? "enable" : "disable")
+ str_enable_disable(E)
@str_enable_disable_r depends on !patch@
expression E;
position P;
@@
* E@P ? "enable" : "disable"
@script:python depends on report@
p << str_enable_disable_r.P;
e << str_enable_disable_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_enable_disable(%s)" % e)
@str_enabled_disabled depends on patch@
expression E;
@@
- ((E) ? "enabled" : "disabled")
+ str_enabled_disabled(E)
@str_enabled_disabled_r depends on !patch@
expression E;
position P;
@@
* E@P ? "enabled" : "disabled"
@script:python depends on report@
p << str_enabled_disabled_r.P;
e << str_enabled_disabled_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_enabled_disabled(%s)" % e)
@str_read_write depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "read" : "write")
+ str_read_write(E)
@str_read_write_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "read" : "write"
@script:python depends on report@
p << str_read_write_r.P;
e << str_read_write_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_read_write(%s)" % e)
@str_write_read depends on patch disable neg_if_exp@
expression E;
@@
- ((E) ? "write" : "read")
+ str_write_read(E)
@str_write_read_r depends on !patch disable neg_if_exp@
expression E;
position P;
@@
* E@P ? "write" : "read"
@script:python depends on report@
p << str_write_read_r.P;
e << str_write_read_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_write_read(%s)" % e)
@str_on_off depends on patch@
expression E;
@@
- ((E) ? "on" : "off")
+ str_on_off(E)
@str_on_off_r depends on !patch@
expression E;
position P;
@@
* E@P ? "on" : "off"
@script:python depends on report@
p << str_on_off_r.P;
e << str_on_off_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_on_off(%s)" % e)
@str_yes_no depends on patch@
expression E;
@@
- ((E) ? "yes" : "no")
+ str_yes_no(E)
@str_yes_no_r depends on !patch@
expression E;
position P;
@@
* E@P ? "yes" : "no"
@script:python depends on report@
p << str_yes_no_r.P;
e << str_yes_no_r.E;
@@
coccilib.report.print_report(p[0], "opportunity for str_yes_no(%s)" % e)
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0
///
/// Use vma_pages function on vma object instead of explicit computation.
///
// Confidence: High
// Keywords: vma_pages vma
// Comment: Based on resource_size.cocci
virtual context
virtual patch
virtual org
virtual report
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@r_context depends on context && !patch && !org && !report@
struct vm_area_struct *vma;
@@
* (vma->vm_end - vma->vm_start) >> PAGE_SHIFT
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@r_patch depends on !context && patch && !org && !report@
struct vm_area_struct *vma;
@@
- ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT)
+ vma_pages(vma)
//----------------------------------------------------------
// For org mode
//----------------------------------------------------------
@r_org depends on !context && !patch && (org || report)@
struct vm_area_struct *vma;
position p;
@@
(vma->vm_end@p - vma->vm_start) >> PAGE_SHIFT
@script:python depends on report@
p << r_org.p;
x << r_org.vma;
@@
msg="WARNING: Consider using vma_pages helper on %s" % (x)
coccilib.report.print_report(p[0], msg)
@script:python depends on org@
p << r_org.p;
x << r_org.vma;
@@
msg="WARNING: Consider using vma_pages helper on %s" % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find missing clk_puts.
///
//# This only signals a missing clk_put when there is a clk_put later
//# in the same function.
//# False positives can be due to loops.
//
// Confidence: Moderate
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options:
virtual context
virtual org
virtual report
@clk@
expression e;
statement S,S1;
int ret;
position p1,p2,p3;
@@
e = clk_get@p1(...)
... when != clk_put(e)
if (<+...e...+>) S
... when any
when != clk_put(e)
when != if (...) { ... clk_put(e); ... }
(
if (ret == 0) S1
|
if (...)
{ ...
return 0; }
|
if (...)
{ ...
return <+...e...+>; }
|
*if@p2 (...)
{ ... when != clk_put(e)
when forall
return@p3 ...; }
)
... when any
clk_put(e);
@script:python depends on org@
p1 << clk.p1;
p2 << clk.p2;
p3 << clk.p3;
@@
cocci.print_main("clk_get",p1)
cocci.print_secs("if",p2)
cocci.print_secs("needed clk_put",p3)
@script:python depends on report@
p1 << clk.p1;
p2 << clk.p2;
p3 << clk.p3;
@@
msg = "ERROR: missing clk_put; clk_get on line %s and execution via conditional on line %s" % (p1[0].line,p2[0].line)
coccilib.report.print_report(p3[0],msg)
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find uses of standard freeing functons on values allocated using devm_
/// functions. Values allocated using the devm_functions are freed when
/// the device is detached, and thus the use of the standard freeing
/// function would cause a double free.
/// See Documentation/driver-api/driver-model/devres.rst for more information.
///
/// A difficulty of detecting this problem is that the standard freeing
/// function might be called from a different function than the one
/// containing the allocation function. It is thus necessary to make the
/// connection between the allocation function and the freeing function.
/// Here this is done using the specific argument text, which is prone to
/// false positives. There is no rule for the request_region and
/// request_mem_region variants because this heuristic seems to be a bit
/// less reliable in these cases.
///
// Confidence: Moderate
// Copyright: (C) 2011 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2011 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
virtual context
@r depends on context || org || report@
expression x;
@@
(
x = devm_kmalloc(...)
|
x = devm_kvasprintf(...)
|
x = devm_kasprintf(...)
|
x = devm_kzalloc(...)
|
x = devm_kmalloc_array(...)
|
x = devm_kcalloc(...)
|
x = devm_kstrdup(...)
|
x = devm_kmemdup(...)
|
x = devm_get_free_pages(...)
|
x = devm_request_irq(...)
|
x = devm_ioremap(...)
|
x = devm_ioport_map(...)
)
@safe depends on context || org || report exists@
expression x;
position p;
@@
(
x = kmalloc(...)
|
x = kvasprintf(...)
|
x = kasprintf(...)
|
x = kzalloc(...)
|
x = kmalloc_array(...)
|
x = kcalloc(...)
|
x = kstrdup(...)
|
x = kmemdup(...)
|
x = get_free_pages(...)
|
x = request_irq(...)
|
x = ioremap(...)
|
x = ioport_map(...)
)
...
(
kfree@p(x)
|
kfree_sensitive@p(x)
|
krealloc@p(x, ...)
|
free_pages@p(x, ...)
|
free_page@p(x)
|
free_irq@p(x)
|
iounmap@p(x)
|
ioport_unmap@p(x)
)
@pb@
expression r.x;
position p != safe.p;
@@
(
* kfree@p(x)
|
* kfree_sensitive@p(x)
|
* krealloc@p(x, ...)
|
* free_pages@p(x, ...)
|
* free_page@p(x)
|
* free_irq@p(x)
|
* iounmap@p(x)
|
* ioport_unmap@p(x)
)
@script:python depends on org@
p << pb.p;
@@
msg="WARNING: invalid free of devm_ allocated data"
coccilib.org.print_todo(p[0], msg)
@script:python depends on report@
p << pb.p;
@@
msg="WARNING: invalid free of devm_ allocated data"
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Since commit b37a46683739 ("netdevice: add the case if dev is NULL"),
/// NULL check before dev_{put, hold} functions is not needed.
///
/// Based on ifnullfree.cocci by Fabian Frederick.
///
// Copyright: (C) 2022 Ziyang Xuan.
// Comments: -
// Options: --no-includes --include-headers
// Version min: 5.15
virtual patch
virtual org
virtual report
virtual context
@r2 depends on patch@
expression E;
@@
- if (E != NULL)
(
__dev_put(E);
|
dev_put(E);
|
dev_put_track(E, ...);
|
__dev_hold(E);
|
dev_hold(E);
|
dev_hold_track(E, ...);
)
@r depends on context || report || org @
expression E;
position p;
@@
* if (E != NULL)
* \(__dev_put@p\|dev_put@p\|dev_put_track@p\|__dev_hold@p\|dev_hold@p\|
* dev_hold_track@p\)(E, ...);
@script:python depends on org@
p << r.p;
@@
cocci.print_main("NULL check before dev_{put, hold} functions is not needed", p)
@script:python depends on report@
p << r.p;
@@
msg = "WARNING: NULL check before dev_{put, hold} functions is not needed."
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-2.0-only
/// NULL check before some freeing functions is not needed.
///
/// Based on checkpatch warning
/// "kfree(NULL) is safe this check is probably not required"
/// and kfreeaddr.cocci by Julia Lawall.
///
// Copyright: (C) 2014 Fabian Frederick.
// Comments: -
// Options: --no-includes --include-headers
virtual patch
virtual org
virtual report
virtual context
@r2 depends on patch@
expression E;
@@
- if (E != NULL)
(
kfree(E);
|
kvfree(E);
|
kfree_sensitive(E);
|
kvfree_sensitive(E, ...);
|
vfree(E);
|
debugfs_remove(E);
|
debugfs_remove_recursive(E);
|
usb_free_urb(E);
|
kmem_cache_destroy(E);
|
mempool_destroy(E);
|
dma_pool_destroy(E);
)
@r depends on context || report || org @
expression E;
position p;
@@
* if (E != NULL)
* \(kfree@p\|kvfree@p\|kfree_sensitive@p\|kvfree_sensitive@p\|vfree@p\|
* debugfs_remove@p\|debugfs_remove_recursive@p\|
* usb_free_urb@p\|kmem_cache_destroy@p\|mempool_destroy@p\|
* dma_pool_destroy@p\)(E, ...);
@script:python depends on org@
p << r.p;
@@
cocci.print_main("NULL check before that freeing function is not needed", p)
@script:python depends on report@
p << r.p;
@@
msg = "WARNING: NULL check before some freeing functions is not needed."
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find missing iounmaps.
///
//# This only signals a missing iounmap when there is an iounmap later
//# in the same function.
//# False positives can be due to loops.
//
// Confidence: Moderate
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options:
virtual context
virtual org
virtual report
@iom@
expression e;
statement S,S1;
int ret;
position p1,p2,p3;
@@
e = \(ioremap@p1\)(...)
... when != iounmap(e)
if (<+...e...+>) S
... when any
when != iounmap(e)
when != if (...) { ... iounmap(e); ... }
(
if (ret == 0) S1
|
if (...)
{ ...
return 0; }
|
if (...)
{ ...
return <+...e...+>; }
|
*if@p2 (...)
{ ... when != iounmap(e)
when forall
return@p3 ...; }
)
... when any
iounmap(e);
@script:python depends on org@
p1 << iom.p1;
p2 << iom.p2;
p3 << iom.p3;
@@
cocci.print_main("ioremap",p1)
cocci.print_secs("if",p2)
cocci.print_secs("needed iounmap",p3)
@script:python depends on report@
p1 << iom.p1;
p2 << iom.p2;
p3 << iom.p3;
@@
msg = "ERROR: missing iounmap; ioremap on line %s and execution via conditional on line %s" % (p1[0].line,p2[0].line)
coccilib.report.print_report(p3[0],msg)
@@ -0,0 +1,134 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find a use after free.
//# Values of variables may imply that some
//# execution paths are not possible, resulting in false positives.
//# Another source of false positives are macros such as
//# SCTP_DBG_OBJCNT_DEC that do not actually evaluate their argument
///
// Confidence: Moderate
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
@free@
expression E;
position p1;
@@
(
kfree@p1(E)
|
kfree_sensitive@p1(E)
)
@print expression@
constant char [] c;
expression free.E,E2;
type T;
position p;
identifier f;
@@
(
f(...,c,...,(T)E@p,...)
|
E@p == E2
|
E@p != E2
|
E2 == E@p
|
E2 != E@p
|
!E@p
|
E@p || ...
)
@sz@
expression free.E;
position p;
@@
sizeof(<+...E@p...+>)
@loop exists@
expression E;
identifier l;
position ok;
@@
while (1) { ...
(
kfree@ok(E)
|
kfree_sensitive@ok(E)
)
... when != break;
when != goto l;
when forall
}
@r exists@
expression free.E, subE<=free.E, E2;
expression E1;
iterator iter;
statement S;
position free.p1!=loop.ok,p2!={print.p,sz.p};
@@
(
kfree@p1(E,...)
|
kfree_sensitive@p1(E,...)
)
...
(
iter(...,subE,...) S // no use
|
list_remove_head(E1,subE,...)
|
subE = E2
|
subE++
|
++subE
|
--subE
|
subE--
|
&subE
|
BUG(...)
|
BUG_ON(...)
|
return_VALUE(...)
|
return_ACPI_STATUS(...)
|
E@p2 // bad use
)
@script:python depends on org@
p1 << free.p1;
p2 << r.p2;
@@
cocci.print_main("kfree",p1)
cocci.print_secs("ref",p2)
@script:python depends on report@
p1 << free.p1;
p2 << r.p2;
@@
msg = "ERROR: reference preceded by free on line %s" % (p1[0].line)
coccilib.report.print_report(p2[0],msg)
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Free of a structure field
///
// Confidence: High
// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
virtual context
@r depends on context || report || org @
expression e;
identifier f;
position p;
@@
(
* kfree@p(&e->f)
|
* kfree_sensitive@p(&e->f)
)
@script:python depends on org@
p << r.p;
@@
cocci.print_main("kfree",p)
@script:python depends on report@
p << r.p;
@@
msg = "ERROR: invalid free of structure field"
coccilib.report.print_report(p[0],msg)
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find missing pci_free_consistent for every pci_alloc_consistent.
///
// Confidence: Moderate
// Copyright: (C) 2013 Petr Strnad.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Keywords: pci_free_consistent, pci_alloc_consistent
// Options: --no-includes --include-headers
virtual report
virtual org
@search@
local idexpression id;
expression x,y,z,e;
position p1,p2;
type T;
@@
id = pci_alloc_consistent@p1(x,y,&z)
... when != e = id
if (id == NULL || ...) { ... return ...; }
... when != pci_free_consistent(x,y,id,z)
when != if (id) { ... pci_free_consistent(x,y,id,z) ... }
when != if (y) { ... pci_free_consistent(x,y,id,z) ... }
when != e = (T)id
when exists
(
return 0;
|
return 1;
|
return id;
|
return@p2 ...;
)
@script:python depends on report@
p1 << search.p1;
p2 << search.p2;
@@
msg = "ERROR: missing pci_free_consistent; pci_alloc_consistent on line %s and return without freeing on line %s" % (p1[0].line,p2[0].line)
coccilib.report.print_report(p2[0],msg)
@script:python depends on org@
p1 << search.p1;
p2 << search.p2;
@@
msg = "ERROR: missing pci_free_consistent; pci_alloc_consistent on line %s and return without freeing on line %s" % (p1[0].line,p2[0].line)
cocci.print_main(msg,p1)
cocci.print_secs("",p2)
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0
/// Find missing put_device for every of_find_device_by_node.
///
// Confidence: Moderate
// Copyright: (C) 2018-2019 Wen Yang, ZTE.
// 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 != if (id) { ... put_device(&id->dev) ... }
when != e1 = (T)id
when != e1 = (T)(&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)
| &id->dev
);
| 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
+ ", but without a corresponding object release within this function.")
@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)
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Device node iterators put the previous value of the index variable, so an
/// explicit put causes a double put.
///
// Confidence: High
// Copyright: (C) 2015 Julia Lawall, Inria.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
// Requires: 1.0.4
// Keywords: for_each_child_of_node, etc.
// This uses a conjunction, which requires at least coccinelle >= 1.0.4
virtual patch
virtual context
virtual org
virtual report
@r exists@
expression e1,e2;
local idexpression n;
iterator name for_each_node_by_name, for_each_node_by_type,
for_each_compatible_node, for_each_matching_node,
for_each_matching_node_and_match, for_each_child_of_node,
for_each_available_child_of_node, for_each_node_with_property;
iterator i;
position p1,p2;
statement S;
@@
(
(
for_each_node_by_name(n,e1) S
|
for_each_node_by_type(n,e1) S
|
for_each_compatible_node(n,e1,e2) S
|
for_each_matching_node(n,e1) S
|
for_each_matching_node_and_match(n,e1,e2) S
|
for_each_child_of_node(e1,n) S
|
for_each_available_child_of_node(e1,n) S
|
for_each_node_with_property(n,e1) S
)
&
i@p1(...) {
... when != of_node_get(n)
when any
of_node_put@p2(n);
... when any
}
)
@s exists@
local idexpression r.n;
statement S;
position r.p1,r.p2;
iterator i;
@@
of_node_put@p2(n);
... when any
i@p1(..., n, ...)
S
@t depends on s && patch && !context && !org && !report@
local idexpression n;
position r.p2;
@@
- of_node_put@p2(n);
// ----------------------------------------------------------------------------
@t_context depends on s && !patch && (context || org || report)@
local idexpression n;
position r.p2;
position j0;
@@
* of_node_put@j0@p2(n);
// ----------------------------------------------------------------------------
@script:python t_org depends on org@
j0 << t_context.j0;
@@
msg = "ERROR: probable double put."
coccilib.org.print_todo(j0[0], msg)
// ----------------------------------------------------------------------------
@script:python t_report depends on report@
j0 << t_context.j0;
@@
msg = "ERROR: probable double put."
coccilib.report.print_report(j0[0], msg)
@@ -0,0 +1,358 @@
// SPDX-License-Identifier: GPL-2.0-only
// Adds missing of_node_put() before return/break/goto statement within a for_each iterator for child nodes.
//# False positives can be due to function calls within the for_each
//# loop that may encapsulate an of_node_put.
///
// Confidence: High
// Copyright: (C) 2020 Sumera Priyadarsini
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@r@
local idexpression n;
expression e1,e2;
iterator name for_each_node_by_name, for_each_node_by_type,
for_each_compatible_node, for_each_matching_node,
for_each_matching_node_and_match, for_each_child_of_node,
for_each_available_child_of_node, for_each_node_with_property;
iterator i;
statement S;
expression list [n1] es;
@@
(
(
for_each_node_by_name(n,e1) S
|
for_each_node_by_type(n,e1) S
|
for_each_compatible_node(n,e1,e2) S
|
for_each_matching_node(n,e1) S
|
for_each_matching_node_and_match(n,e1,e2) S
|
for_each_child_of_node(e1,n) S
|
for_each_available_child_of_node(e1,n) S
|
for_each_node_with_property(n,e1) S
)
&
i(es,n,...) S
)
@ruleone depends on patch && !context && !org && !report@
local idexpression r.n;
iterator r.i,i1;
expression e;
expression list [r.n1] es;
statement S;
@@
i(es,n,...) {
...
(
of_node_put(n);
|
e = n
|
return n;
|
i1(...,n,...) S
|
- return of_node_get(n);
+ return n;
|
+ of_node_put(n);
? return ...;
)
... when any
}
@ruletwo depends on patch && !context && !org && !report@
local idexpression r.n;
iterator r.i,i1,i2;
expression e,e1;
expression list [r.n1] es;
statement S,S2;
@@
i(es,n,...) {
...
(
of_node_put(n);
|
e = n
|
i1(...,n,...) S
|
+ of_node_put(n);
? break;
)
... when any
}
... when != n
when strict
when forall
(
n = e1;
|
?i2(...,n,...) S2
)
@rulethree depends on patch && !context && !org && !report exists@
local idexpression r.n;
iterator r.i,i1,i2;
expression e,e1;
identifier l;
expression list [r.n1] es;
statement S,S2;
@@
i(es,n,...) {
...
(
of_node_put(n);
|
e = n
|
i1(...,n,...) S
|
+ of_node_put(n);
? goto l;
)
... when any
}
... when exists
l: ... when != n
when strict
when forall
(
n = e1;
|
?i2(...,n,...) S2
)
// ----------------------------------------------------------------------------
@ruleone_context depends on !patch && (context || org || report) exists@
statement S;
expression e;
expression list[r.n1] es;
iterator r.i, i1;
local idexpression r.n;
position j0, j1;
@@
i@j0(es,n,...) {
...
(
of_node_put(n);
|
e = n
|
return n;
|
i1(...,n,...) S
|
return @j1 ...;
)
... when any
}
@ruleone_disj depends on !patch && (context || org || report)@
expression list[r.n1] es;
iterator r.i;
local idexpression r.n;
position ruleone_context.j0, ruleone_context.j1;
@@
* i@j0(es,n,...) {
...
*return @j1...;
... when any
}
@ruletwo_context depends on !patch && (context || org || report) exists@
statement S, S2;
expression e, e1;
expression list[r.n1] es;
iterator r.i, i1, i2;
local idexpression r.n;
position j0, j2;
@@
i@j0(es,n,...) {
...
(
of_node_put(n);
|
e = n
|
i1(...,n,...) S
|
break@j2;
)
... when any
}
... when != n
when strict
when forall
(
n = e1;
|
?i2(...,n,...) S2
)
@ruletwo_disj depends on !patch && (context || org || report)@
statement S2;
expression e1;
expression list[r.n1] es;
iterator r.i, i2;
local idexpression r.n;
position ruletwo_context.j0, ruletwo_context.j2;
@@
* i@j0(es,n,...) {
...
*break @j2;
... when any
}
... when != n
when strict
when forall
(
n = e1;
|
?i2(...,n,...) S2
)
@rulethree_context depends on !patch && (context || org || report) exists@
identifier l;
statement S,S2;
expression e, e1;
expression list[r.n1] es;
iterator r.i, i1, i2;
local idexpression r.n;
position j0, j3;
@@
i@j0(es,n,...) {
...
(
of_node_put(n);
|
e = n
|
i1(...,n,...) S
|
goto l@j3;
)
... when any
}
... when exists
l:
... when != n
when strict
when forall
(
n = e1;
|
?i2(...,n,...) S2
)
@rulethree_disj depends on !patch && (context || org || report) exists@
identifier l;
statement S2;
expression e1;
expression list[r.n1] es;
iterator r.i, i2;
local idexpression r.n;
position rulethree_context.j0, rulethree_context.j3;
@@
* i@j0(es,n,...) {
...
*goto l@j3;
... when any
}
... when exists
l:
... when != n
when strict
when forall
(
n = e1;
|
?i2(...,n,...) S2
)
// ----------------------------------------------------------------------------
@script:python ruleone_org depends on org@
i << r.i;
j0 << ruleone_context.j0;
j1 << ruleone_context. j1;
@@
msg = "WARNING: Function \"%s\" should have of_node_put() before return " % (i)
coccilib.org.print_safe_todo(j0[0], msg)
coccilib.org.print_link(j1[0], "")
@script:python ruletwo_org depends on org@
i << r.i;
j0 << ruletwo_context.j0;
j2 << ruletwo_context.j2;
@@
msg = "WARNING: Function \"%s\" should have of_node_put() before break " % (i)
coccilib.org.print_safe_todo(j0[0], msg)
coccilib.org.print_link(j2[0], "")
@script:python rulethree_org depends on org@
i << r.i;
j0 << rulethree_context.j0;
j3 << rulethree_context.j3;
@@
msg = "WARNING: Function \"%s\" should have of_node_put() before goto " % (i)
coccilib.org.print_safe_todo(j0[0], msg)
coccilib.org.print_link(j3[0], "")
// ----------------------------------------------------------------------------
@script:python ruleone_report depends on report@
i << r.i;
j0 << ruleone_context.j0;
j1 << ruleone_context.j1;
@@
msg = "WARNING: Function \"%s\" should have of_node_put() before return around line %s." % (i, j1[0].line)
coccilib.report.print_report(j0[0], msg)
@script:python ruletwo_report depends on report@
i << r.i;
j0 << ruletwo_context.j0;
j2 << ruletwo_context.j2;
@@
msg = "WARNING: Function \"%s\" should have of_node_put() before break around line %s." % (i,j2[0].line)
coccilib.report.print_report(j0[0], msg)
@script:python rulethree_report depends on report@
i << r.i;
j0 << rulethree_context.j0;
j3 << rulethree_context.j3;
@@
msg = "WARNING: Function \"%s\" should have of_node_put() before goto around lines %s." % (i,j3[0].line)
coccilib.report.print_report(j0[0], msg)
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Many iterators have the property that the first argument is always bound
/// to a real list element, never NULL.
//# False positives arise for some iterators that do not have this property,
//# or in cases when the loop cursor is reassigned. The latter should only
//# happen when the matched code is on the way to a loop exit (break, goto,
//# or return).
///
// Confidence: Moderate
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@depends on patch@
iterator I;
expression x,E,E1,E2;
statement S,S1,S2;
@@
I(x,...) { <...
(
- if (x == NULL && ...) S
|
- if (x != NULL || ...)
S
|
- (x == NULL) ||
E
|
- (x != NULL) &&
E
|
- (x == NULL && ...) ? E1 :
E2
|
- (x != NULL || ...) ?
E1
- : E2
|
- if (x == NULL && ...) S1 else
S2
|
- if (x != NULL || ...)
S1
- else S2
|
+ BAD(
x == NULL
+ )
|
+ BAD(
x != NULL
+ )
)
...> }
@r depends on !patch exists@
iterator I;
expression x,E;
position p1,p2;
@@
*I@p1(x,...)
{ ... when != x = E
(
* x@p2 == NULL
|
* x@p2 != NULL
)
... when any
}
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("iterator-bound variable",p1)
cocci.print_secs("useless NULL test",p2)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "ERROR: iterator variable bound on line %s cannot be NULL" % (p1[0].line)
coccilib.report.print_report(p2[0], msg)
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0-only
/// list_for_each_entry uses its first argument to get from one element of
/// the list to the next, so it is usually not a good idea to reassign it.
/// The first rule finds such a reassignment and the second rule checks
/// that there is a path from the reassignment back to the top of the loop.
///
// Confidence: High
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r exists@
iterator name list_for_each_entry;
expression x,E;
position p1,p2;
@@
list_for_each_entry@p1(x,...) { <... x =@p2 E ...> }
@depends on context && !org && !report@
expression x,E;
position r.p1,r.p2;
statement S;
@@
*x =@p2 E
...
list_for_each_entry@p1(x,...) S
// ------------------------------------------------------------------------
@back depends on (org || report) && !context exists@
expression x,E;
position r.p1,r.p2;
statement S;
@@
x =@p2 E
...
list_for_each_entry@p1(x,...) S
@script:python depends on back && org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("iterator",p1)
cocci.print_secs("update",p2)
@script:python depends on back && report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "iterator with update on line %s" % (p2[0].line)
coccilib.report.print_report(p1[0],msg)
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: GPL-2.0-only
/// If list_for_each_entry, etc complete a traversal of the list, the iterator
/// variable ends up pointing to an address at an offset from the list head,
/// and not a meaningful structure. Thus this value should not be used after
/// the end of the iterator.
//#False positives arise when there is a goto in the iterator and the
//#reported reference is at the label of this goto. Some flag tests
//#may also cause a report to be a false positive.
///
// Confidence: Moderate
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LIP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r exists@
identifier c,member;
expression E,x;
iterator name list_for_each_entry;
iterator name list_for_each_entry_reverse;
iterator name list_for_each_entry_continue;
iterator name list_for_each_entry_continue_reverse;
iterator name list_for_each_entry_from;
iterator name list_for_each_entry_safe;
iterator name list_for_each_entry_safe_continue;
iterator name list_for_each_entry_safe_from;
iterator name list_for_each_entry_safe_reverse;
iterator name hlist_for_each_entry;
iterator name hlist_for_each_entry_continue;
iterator name hlist_for_each_entry_from;
iterator name hlist_for_each_entry_safe;
statement S;
position p1,p2;
type T;
@@
(
list_for_each_entry@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_reverse@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_continue@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_continue_reverse@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_from@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_safe@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_safe_continue@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_safe_from@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_safe_reverse@p1(c,...,member) { ... when != break;
when forall
when strict
}
)
...
(
list_for_each_entry(c,...) S
|
list_for_each_entry_reverse(c,...) S
|
list_for_each_entry_continue(c,...) S
|
list_for_each_entry_continue_reverse(c,...) S
|
list_for_each_entry_from(c,...) S
|
list_for_each_entry_safe(c,...) S
|
list_for_each_entry_safe(x,c,...) S
|
list_for_each_entry_safe_continue(c,...) S
|
list_for_each_entry_safe_continue(x,c,...) S
|
list_for_each_entry_safe_from(c,...) S
|
list_for_each_entry_safe_from(x,c,...) S
|
list_for_each_entry_safe_reverse(c,...) S
|
list_for_each_entry_safe_reverse(x,c,...) S
|
hlist_for_each_entry(c,...) S
|
hlist_for_each_entry_continue(c,...) S
|
hlist_for_each_entry_from(c,...) S
|
hlist_for_each_entry_safe(c,...) S
|
list_remove_head(x,c,...)
|
list_entry_is_head(c,...)
|
sizeof(<+...c...+>)
|
&c->member
|
T c;
|
c = E
|
*c@p2
)
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("invalid iterator index reference",p2)
cocci.print_secs("iterator",p1)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "ERROR: invalid reference to the index variable of the iterator on line %s" % (p1[0].line)
coccilib.report.print_report(p2[0], msg)
@@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find functions that refer to GFP_KERNEL but are called with locks held.
//# The proposed change of converting the GFP_KERNEL is not necessarily the
//# correct one. It may be desired to unlock the lock, or to not call the
//# function under the lock in the first place.
///
// Confidence: Moderate
// Copyright: (C) 2012 Nicolas Palix.
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@gfp exists@
identifier fn;
position p;
@@
fn(...) {
... when != read_unlock_irq(...)
when != write_unlock_irq(...)
when != read_unlock_irqrestore(...)
when != write_unlock_irqrestore(...)
when != spin_unlock(...)
when != spin_unlock_irq(...)
when != spin_unlock_irqrestore(...)
when != local_irq_enable(...)
when any
GFP_KERNEL@p
... when any
}
@locked exists@
identifier gfp.fn;
position p1,p2;
@@
(
read_lock_irq@p1
|
write_lock_irq@p1
|
read_lock_irqsave@p1
|
write_lock_irqsave@p1
|
spin_lock@p1
|
spin_trylock@p1
|
spin_lock_irq@p1
|
spin_lock_irqsave@p1
|
local_irq_disable@p1
)
(...)
... when != read_unlock_irq(...)
when != write_unlock_irq(...)
when != read_unlock_irqrestore(...)
when != write_unlock_irqrestore(...)
when != spin_unlock(...)
when != spin_unlock_irq(...)
when != spin_unlock_irqrestore(...)
when != local_irq_enable(...)
fn@p2(...)
@depends on locked && patch@
position gfp.p;
@@
- GFP_KERNEL@p
+ GFP_ATOMIC
@depends on locked && !patch@
position gfp.p;
@@
* GFP_KERNEL@p
@script:python depends on !patch && org@
p << gfp.p;
fn << gfp.fn;
p1 << locked.p1;
p2 << locked.p2;
@@
cocci.print_main("lock",p1)
cocci.print_secs("call",p2)
cocci.print_secs("GFP_KERNEL",p)
@script:python depends on !patch && report@
p << gfp.p;
fn << gfp.fn;
p1 << locked.p1;
p2 << locked.p2;
@@
msg = "ERROR: function %s called on line %s inside lock on line %s but uses GFP_KERNEL" % (fn,p2[0].line,p1[0].line)
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find double locks. False positives may occur when some paths cannot
/// occur at execution, due to the values of variables, and when there is
/// an intervening function call that releases the lock.
///
// Confidence: Moderate
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
@locked@
position p1;
expression E1;
position p;
@@
(
mutex_lock@p1
|
mutex_trylock@p1
|
spin_lock@p1
|
spin_trylock@p1
|
read_lock@p1
|
read_trylock@p1
|
write_lock@p1
|
write_trylock@p1
) (E1@p,...);
@balanced@
position p1 != locked.p1;
position locked.p;
identifier lock,unlock;
expression x <= locked.E1;
expression E,locked.E1;
expression E2;
@@
if (E) {
<+... when != E1
lock(E1@p,...)
...+>
}
... when != E1
when != \(x = E2\|&x\)
when forall
if (E) {
<+... when != E1
unlock@p1(E1,...)
...+>
}
@r depends on !balanced exists@
expression x <= locked.E1;
expression locked.E1;
expression E2;
identifier lock;
position locked.p,p1,p2;
@@
lock@p1 (E1@p,...);
... when != E1
when != \(x = E2\|&x\)
lock@p2 (E1,...);
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
lock << r.lock;
@@
cocci.print_main(lock,p1)
cocci.print_secs("second lock",p2)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
lock << r.lock;
@@
msg = "second lock on line %s" % (p2[0].line)
coccilib.report.print_report(p1[0],msg)
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find nested lock+irqsave functions that use the same flags variables
///
// Confidence: High
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r exists@
expression lock1,lock2,flags;
position p1,p2;
@@
(
spin_lock_irqsave@p1(lock1,flags)
|
read_lock_irqsave@p1(lock1,flags)
|
write_lock_irqsave@p1(lock1,flags)
)
... when != flags
(
spin_lock_irqsave(lock1,flags)
|
read_lock_irqsave(lock1,flags)
|
write_lock_irqsave(lock1,flags)
|
spin_lock_irqsave@p2(lock2,flags)
|
read_lock_irqsave@p2(lock2,flags)
|
write_lock_irqsave@p2(lock2,flags)
)
@d exists@
expression f <= r.flags;
expression lock1,lock2,flags;
position r.p1, r.p2;
@@
(
*spin_lock_irqsave@p1(lock1,flags)
|
*read_lock_irqsave@p1(lock1,flags)
|
*write_lock_irqsave@p1(lock1,flags)
)
... when != f
(
*spin_lock_irqsave@p2(lock2,flags)
|
*read_lock_irqsave@p2(lock2,flags)
|
*write_lock_irqsave@p2(lock2,flags)
)
// ----------------------------------------------------------------------
@script:python depends on d && org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("original lock",p1)
cocci.print_secs("nested lock+irqsave that reuses flags",p2)
@script:python depends on d && report@
p1 << r.p1;
p2 << r.p2;
@@
msg="ERROR: nested lock+irqsave that reuses flags from line %s." % (p1[0].line)
coccilib.report.print_report(p2[0], msg)
@@ -0,0 +1,99 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find missing unlocks. This semantic match considers the specific case
/// where the unlock is missing from an if branch, and there is a lock
/// before the if and an unlock after the if. False positives are due to
/// cases where the if branch represents a case where the function is
/// supposed to exit with the lock held, or where there is some preceding
/// function call that releases the lock.
///
// Confidence: Moderate
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@prelocked@
position p1,p;
expression E1;
@@
(
mutex_lock@p1
|
mutex_trylock@p1
|
spin_lock@p1
|
spin_trylock@p1
|
read_lock@p1
|
read_trylock@p1
|
write_lock@p1
|
write_trylock@p1
|
read_lock_irq@p1
|
write_lock_irq@p1
|
read_lock_irqsave@p1
|
write_lock_irqsave@p1
|
spin_lock_irq@p1
|
spin_lock_irqsave@p1
) (E1@p,...);
@looped@
position r;
@@
for(...;...;...) { <+... return@r ...; ...+> }
@err exists@
expression E1;
position prelocked.p;
position up != prelocked.p1;
position r!=looped.r;
identifier lock,unlock;
@@
*lock(E1@p,...);
... when != E1
when any
if (...) {
... when != E1
* return@r ...;
}
... when != E1
when any
*unlock@up(E1,...);
@script:python depends on org@
p << prelocked.p1;
lock << err.lock;
unlock << err.unlock;
p2 << err.r;
@@
cocci.print_main(lock,p)
cocci.print_secs(unlock,p2)
@script:python depends on report@
p << prelocked.p1;
lock << err.lock;
unlock << err.unlock;
p2 << err.r;
@@
msg = "preceding lock on line %s" % (p[0].line)
coccilib.report.print_report(p2[0],msg)
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0-only
//
/// Adds missing MODULE_IMPORT_NS statements to source files
///
/// This script is usually called from scripts/nsdeps with -D ns=<namespace> to
/// add a missing namespace tag to a module source file.
///
virtual nsdeps
virtual report
@has_ns_import@
declarer name MODULE_IMPORT_NS;
identifier virtual.ns;
@@
MODULE_IMPORT_NS(ns);
// Add missing imports, but only adjacent to a MODULE_LICENSE statement.
// That ensures we are adding it only to the main module source file.
@do_import depends on !has_ns_import && nsdeps@
declarer name MODULE_LICENSE;
expression license;
identifier virtual.ns;
@@
MODULE_LICENSE(license);
+ MODULE_IMPORT_NS(ns);
// Dummy rule for report mode that would otherwise be empty and make spatch
// fail ("No rules apply.")
@script:python depends on report@
@@
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element
///
//# This makes an effort to find cases where ARRAY_SIZE can be used such as
//# where there is a division of sizeof the array by the sizeof its first
//# element or by any indexed element or the element type. It replaces the
//# division of the two sizeofs by ARRAY_SIZE.
//
// Confidence: High
// Copyright: (C) 2014 Himangi Saraogi.
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@i@
@@
#include <linux/kernel.h>
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@depends on i&&context@
type T;
T[] E;
@@
(
* (sizeof(E)/sizeof(*E))
|
* (sizeof(E)/sizeof(E[...]))
|
* (sizeof(E)/sizeof(T))
)
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@depends on i&&patch@
type T;
T[] E;
@@
(
- (sizeof(E)/sizeof(*E))
+ ARRAY_SIZE(E)
|
- (sizeof(E)/sizeof(E[...]))
+ ARRAY_SIZE(E)
|
- (sizeof(E)/sizeof(T))
+ ARRAY_SIZE(E)
)
//----------------------------------------------------------
// For org and report mode
//----------------------------------------------------------
@r depends on (org || report)@
type T;
T[] E;
position p;
@@
(
(sizeof(E)@p /sizeof(*E))
|
(sizeof(E)@p /sizeof(E[...]))
|
(sizeof(E)@p /sizeof(T))
)
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING should use ARRAY_SIZE")
@script:python depends on report@
p << r.p;
@@
msg="WARNING: Use ARRAY_SIZE"
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,209 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Check for array_size(), array3_size(), struct_size() duplicates.
/// These patterns are detected:
/// 1. An opencoded expression is used before array_size() to compute the same size
/// 2. An opencoded expression is used after array_size() to compute the same size
/// From security point of view only first case is relevant. These functions
/// perform arithmetic overflow check. Thus, if we use an opencoded expression
/// before a call to the *_size() function we can miss an overflow.
///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers --no-loops
virtual context
virtual report
virtual org
@as@
expression E1, E2;
@@
array_size(E1, E2)
@as_next@
expression subE1 <= as.E1;
expression subE2 <= as.E2;
expression as.E1, as.E2, E3;
assignment operator aop;
position p1, p2;
@@
* E1 * E2@p1
... when != \(subE1\|subE2\) aop E3
when != &\(subE1\|subE2\)
* array_size(E1, E2)@p2
@script:python depends on report@
p1 << as_next.p1;
p2 << as_next.p2;
@@
msg = "WARNING: array_size is used later (line %s) to compute the same size" % (p2[0].line)
coccilib.report.print_report(p1[0], msg)
@script:python depends on org@
p1 << as_next.p1;
p2 << as_next.p2;
@@
msg = "WARNING: array_size is used later (line %s) to compute the same size" % (p2[0].line)
coccilib.org.print_todo(p1[0], msg)
@as_prev@
expression subE1 <= as.E1;
expression subE2 <= as.E2;
expression as.E1, as.E2, E3;
assignment operator aop;
position p1, p2;
@@
* array_size(E1, E2)@p1
... when != \(subE1\|subE2\) aop E3
when != &\(subE1\|subE2\)
* E1 * E2@p2
@script:python depends on report@
p1 << as_prev.p1;
p2 << as_prev.p2;
@@
msg = "WARNING: array_size is already used (line %s) to compute the same size" % (p1[0].line)
coccilib.report.print_report(p2[0], msg)
@script:python depends on org@
p1 << as_prev.p1;
p2 << as_prev.p2;
@@
msg = "WARNING: array_size is already used (line %s) to compute the same size" % (p1[0].line)
coccilib.org.print_todo(p2[0], msg)
@as3@
expression E1, E2, E3;
@@
array3_size(E1, E2, E3)
@as3_next@
expression subE1 <= as3.E1;
expression subE2 <= as3.E2;
expression subE3 <= as3.E3;
expression as3.E1, as3.E2, as3.E3, E4;
assignment operator aop;
position p1, p2;
@@
* E1 * E2 * E3@p1
... when != \(subE1\|subE2\|subE3\) aop E4
when != &\(subE1\|subE2\|subE3\)
* array3_size(E1, E2, E3)@p2
@script:python depends on report@
p1 << as3_next.p1;
p2 << as3_next.p2;
@@
msg = "WARNING: array3_size is used later (line %s) to compute the same size" % (p2[0].line)
coccilib.report.print_report(p1[0], msg)
@script:python depends on org@
p1 << as3_next.p1;
p2 << as3_next.p2;
@@
msg = "WARNING: array3_size is used later (line %s) to compute the same size" % (p2[0].line)
coccilib.org.print_todo(p1[0], msg)
@as3_prev@
expression subE1 <= as3.E1;
expression subE2 <= as3.E2;
expression subE3 <= as3.E3;
expression as3.E1, as3.E2, as3.E3, E4;
assignment operator aop;
position p1, p2;
@@
* array3_size(E1, E2, E3)@p1
... when != \(subE1\|subE2\|subE3\) aop E4
when != &\(subE1\|subE2\|subE3\)
* E1 * E2 * E3@p2
@script:python depends on report@
p1 << as3_prev.p1;
p2 << as3_prev.p2;
@@
msg = "WARNING: array3_size is already used (line %s) to compute the same size" % (p1[0].line)
coccilib.report.print_report(p2[0], msg)
@script:python depends on org@
p1 << as3_prev.p1;
p2 << as3_prev.p2;
@@
msg = "WARNING: array3_size is already used (line %s) to compute the same size" % (p1[0].line)
coccilib.org.print_todo(p2[0], msg)
@ss@
expression E1, E2, E3;
@@
struct_size(E1, E2, E3)
@ss_next@
expression subE3 <= ss.E3;
expression ss.E1, ss.E2, ss.E3, E4;
assignment operator aop;
position p1, p2;
@@
* E1 * E2 + E3@p1
... when != subE3 aop E4
when != &subE3
* struct_size(E1, E2, E3)@p2
@script:python depends on report@
p1 << ss_next.p1;
p2 << ss_next.p2;
@@
msg = "WARNING: struct_size is used later (line %s) to compute the same size" % (p2[0].line)
coccilib.report.print_report(p1[0], msg)
@script:python depends on org@
p1 << ss_next.p1;
p2 << ss_next.p2;
@@
msg = "WARNING: struct_size is used later (line %s) to compute the same size" % (p2[0].line)
coccilib.org.print_todo(p1[0], msg)
@ss_prev@
expression subE3 <= ss.E3;
expression ss.E1, ss.E2, ss.E3, E4;
assignment operator aop;
position p1, p2;
@@
* struct_size(E1, E2, E3)@p1
... when != subE3 aop E4
when != &subE3
* E1 * E2 + E3@p2
@script:python depends on report@
p1 << ss_prev.p1;
p2 << ss_prev.p2;
@@
msg = "WARNING: struct_size is already used (line %s) to compute the same size" % (p1[0].line)
coccilib.report.print_report(p2[0], msg)
@script:python depends on org@
p1 << ss_prev.p1;
p2 << ss_prev.p2;
@@
msg = "WARNING: struct_size is already used (line %s) to compute the same size" % (p1[0].line)
coccilib.org.print_todo(p2[0], msg)
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Correct the size argument to alloc functions
///
//# This makes an effort to find cases where the argument to sizeof is wrong
//# in memory allocation functions by checking the type of the allocated memory
//# when it is a double pointer and ensuring the sizeof argument takes a pointer
//# to the the memory being allocated. There are false positives in cases the
//# sizeof argument is not used in constructing the return value. The result
//# may need some reformatting.
//
// Confidence: Moderate
// Copyright: (C) 2014 Himangi Saraogi.
// Comments:
// Options:
virtual patch
virtual context
virtual org
virtual report
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@depends on context disable sizeof_type_expr@
type T;
T **x;
@@
x =
<+...sizeof(
* T
)...+>
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@depends on patch disable sizeof_type_expr@
type T;
T **x;
@@
x =
<+...sizeof(
- T
+ *x
)...+>
//----------------------------------------------------------
// For org and report mode
//----------------------------------------------------------
@r depends on (org || report) disable sizeof_type_expr@
type T;
T **x;
position p;
@@
x =
<+...sizeof(
T@p
)...+>
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING sizeof argument should be pointer type, not structure type")
@script:python depends on report@
p << r.p;
@@
msg="WARNING: Use correct pointer type argument for sizeof"
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,91 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Remove unneeded conversion to bool
///
//# Relational and logical operators evaluate to bool,
//# explicit conversion is overly verbose and unneeded.
//
// Copyright: (C) 2016 Andrew F. Davis <afd@ti.com>
virtual patch
virtual context
virtual org
virtual report
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@depends on patch@
expression A, B;
symbol true, false;
@@
(
A == B
|
A != B
|
A > B
|
A < B
|
A >= B
|
A <= B
|
A && B
|
A || B
)
- ? true : false
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@r depends on !patch@
expression A, B;
symbol true, false;
position p;
@@
(
A == B
|
A != B
|
A > B
|
A < B
|
A >= B
|
A <= B
|
A && B
|
A || B
)
* ? true : false@p
//----------------------------------------------------------
// For org mode
//----------------------------------------------------------
@script:python depends on r&&org@
p << r.p;
@@
msg = "WARNING: conversion to bool not needed here"
coccilib.org.print_todo(p[0], msg)
//----------------------------------------------------------
// For report mode
//----------------------------------------------------------
@script:python depends on r&&report@
p << r.p;
@@
msg = "WARNING: conversion to bool not needed here"
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: GPL-2.0-only
///Find conditions where if and else branch are functionally
// identical.
//
// There can be false positives in cases where the positional
// information is used (as with lockdep) or where the identity
// is a placeholder for not yet handled cases.
// Unfortunately there also seems to be a tendency to use
// the last if else/else as a "default behavior" - which some
// might consider a legitimate coding pattern. From discussion
// on kernelnewbies though it seems that this is not really an
// accepted pattern and if at all it would need to be commented
//
// In the Linux kernel it does not seem to actually report
// false positives except for those that were documented as
// being intentional.
// the two known cases are:
// arch/sh/kernel/traps_64.c:read_opcode()
// } else if ((pc & 1) == 0) {
// /* SHcompact */
// /* TODO : provide handling for this. We don't really support
// user-mode SHcompact yet, and for a kernel fault, this would
// have to come from a module built for SHcompact. */
// return -EFAULT;
// } else {
// /* misaligned */
// return -EFAULT;
// }
// fs/kernfs/file.c:kernfs_fop_open()
// * Both paths of the branch look the same. They're supposed to
// * look that way and give @of->mutex different static lockdep keys.
// */
// if (has_mmap)
// mutex_init(&of->mutex);
// else
// mutex_init(&of->mutex);
//
// All other cases look like bugs or at least lack of documentation
//
// Confidence: Moderate
// Copyright: (C) 2016 Nicholas Mc Guire, OSADL.
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
@cond@
statement S1;
position p;
@@
* if@p (...) S1 else S1
@script:python depends on org@
p << cond.p;
@@
cocci.print_main("WARNING: possible condition with no effect (if == else)",p)
@script:python depends on report@
p << cond.p;
@@
coccilib.report.print_report(p[0],"WARNING: possible condition with no effect (if == else)")
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-only
/// PTR_ERR should be applied before its argument is reassigned, typically
/// to NULL
///
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
virtual context
@r exists@
expression e,e1;
constant c;
position p1,p2;
@@
*e@p1 = c
... when != e = e1
when != &e
when != true IS_ERR(e)
*PTR_ERR@p2(e)
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("PTR_ERR",p2)
cocci.print_secs("assignment",p1)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "ERROR: PTR_ERR applied after initialization to constant on line %s" % (p1[0].line)
coccilib.report.print_report(p2[0],msg)
@@ -0,0 +1,155 @@
// SPDX-License-Identifier: GPL-2.0-only
/// do_div() does a 64-by-32 division.
/// When the divisor is long, unsigned long, u64, or s64,
/// do_div() truncates it to 32 bits, this means it can test
/// non-zero and be truncated to 0 for division on 64bit platforms.
///
//# This makes an effort to find those inappropriate do_div() calls.
//
// Confidence: Moderate
// Copyright: (C) 2020 Wen Yang, Alibaba.
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@initialize:python@
@@
def get_digit_type_and_value(str):
is_digit = False
value = 0
try:
if (str.isdigit()):
is_digit = True
value = int(str, 0)
elif (str.upper().endswith('ULL')):
is_digit = True
value = int(str[:-3], 0)
elif (str.upper().endswith('LL')):
is_digit = True
value = int(str[:-2], 0)
elif (str.upper().endswith('UL')):
is_digit = True
value = int(str[:-2], 0)
elif (str.upper().endswith('L')):
is_digit = True
value = int(str[:-1], 0)
elif (str.upper().endswith('U')):
is_digit = True
value = int(str[:-1], 0)
except Exception as e:
print('Error:',e)
is_digit = False
value = 0
finally:
return is_digit, value
def filter_out_safe_constants(str):
is_digit, value = get_digit_type_and_value(str)
if (is_digit):
if (value >= 0x100000000):
return True
else:
return False
else:
return True
def construct_warnings(suggested_fun):
msg="WARNING: do_div() does a 64-by-32 division, please consider using %s instead."
return msg % suggested_fun
@depends on context@
expression f;
long l: script:python() { filter_out_safe_constants(l) };
unsigned long ul : script:python() { filter_out_safe_constants(ul) };
u64 ul64 : script:python() { filter_out_safe_constants(ul64) };
s64 sl64 : script:python() { filter_out_safe_constants(sl64) };
@@
(
* do_div(f, l);
|
* do_div(f, ul);
|
* do_div(f, ul64);
|
* do_div(f, sl64);
)
@r depends on (org || report)@
expression f;
position p;
long l: script:python() { filter_out_safe_constants(l) };
unsigned long ul : script:python() { filter_out_safe_constants(ul) };
u64 ul64 : script:python() { filter_out_safe_constants(ul64) };
s64 sl64 : script:python() { filter_out_safe_constants(sl64) };
@@
(
do_div@p(f, l);
|
do_div@p(f, ul);
|
do_div@p(f, ul64);
|
do_div@p(f, sl64);
)
@script:python depends on org@
p << r.p;
ul << r.ul;
@@
coccilib.org.print_todo(p[0], construct_warnings("div64_ul"))
@script:python depends on org@
p << r.p;
l << r.l;
@@
coccilib.org.print_todo(p[0], construct_warnings("div64_long"))
@script:python depends on org@
p << r.p;
ul64 << r.ul64;
@@
coccilib.org.print_todo(p[0], construct_warnings("div64_u64"))
@script:python depends on org@
p << r.p;
sl64 << r.sl64;
@@
coccilib.org.print_todo(p[0], construct_warnings("div64_s64"))
@script:python depends on report@
p << r.p;
ul << r.ul;
@@
coccilib.report.print_report(p[0], construct_warnings("div64_ul"))
@script:python depends on report@
p << r.p;
l << r.l;
@@
coccilib.report.print_report(p[0], construct_warnings("div64_long"))
@script:python depends on report@
p << r.p;
sl64 << r.sl64;
@@
coccilib.report.print_report(p[0], construct_warnings("div64_s64"))
@script:python depends on report@
p << r.p;
ul64 << r.ul64;
@@
coccilib.report.print_report(p[0], construct_warnings("div64_u64"))
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find duplicate field initializations. This has a high rate of false
/// positives due to #ifdefs, which Coccinelle is not aware of in a structure
/// initialization.
///
// Confidence: Low
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise
// Options: --no-includes --include-headers
virtual org
virtual report
@r@
identifier I, s, fld;
position p0,p;
expression E;
@@
struct I s =@p0 { ..., .fld@p = E, ...};
@s@
identifier I, s, r.fld;
position r.p0,p;
expression E;
@@
struct I s =@p0 { ..., .fld@p = E, ...};
@script:python depends on org@
p0 << r.p0;
fld << r.fld;
ps << s.p;
pr << r.p;
@@
if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
cocci.print_main(fld,p0)
cocci.print_secs("s",ps)
cocci.print_secs("r",pr)
@script:python depends on report@
p0 << r.p0;
fld << r.fld;
ps << s.p;
pr << r.p;
@@
if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
msg = "%s: first occurrence line %s, second occurrence line %s" % (fld,ps[0].line,pr[0].line)
coccilib.report.print_report(p0[0],msg)
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Condition !A || A && B is equivalent to !A || B.
///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@r depends on !patch@
expression A, B;
position p;
@@
* !A || (A &&@p B)
@depends on patch@
expression A, B;
@@
!A ||
- (A && B)
+ B
@script:python depends on report@
p << r.p;
@@
coccilib.report.print_report(p[0], "WARNING !A || A && B is equivalent to !A || B")
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING !A || A && B is equivalent to !A || B")
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Zero-length and one-element arrays are deprecated, see
/// Documentation/process/deprecated.rst
/// Flexible-array members should be used instead.
///
//
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS.
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual report
virtual org
virtual patch
@initialize:python@
@@
def relevant(positions):
for p in positions:
if "uapi" in p.file:
return False
return True
@r depends on !patch@
identifier name, array;
type T;
position p : script:python() { relevant(p) };
@@
(
struct name {
...
* T array@p[\(0\|1\)];
};
|
struct {
...
* T array@p[\(0\|1\)];
};
|
union name {
...
* T array@p[\(0\|1\)];
};
|
union {
...
* T array@p[\(0\|1\)];
};
)
@only_field depends on patch@
identifier name, array;
type T;
position q;
@@
(
struct name {@q
T array[0];
};
|
struct {@q
T array[0];
};
)
@depends on patch@
identifier name, array;
type T;
position p : script:python() { relevant(p) };
// position @q with rule "only_field" simplifies
// handling of bitfields, arrays, etc.
position q != only_field.q;
@@
(
struct name {@q
...
T array@p[
- 0
];
};
|
struct {@q
...
T array@p[
- 0
];
};
)
@script: python depends on report@
p << r.p;
@@
msg = "WARNING use flexible-array member instead (https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays)"
coccilib.report.print_report(p[0], msg)
@script: python depends on org@
p << r.p;
@@
msg = "WARNING use flexible-array member instead (https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays)"
coccilib.org.print_todo(p[0], msg)
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find confusingly indented code in or after an if. An if branch should
/// be indented. The code following an if should not be indented.
/// Sometimes, code after an if that is indented is actually intended to be
/// part of the if branch.
///
//# This has a high rate of false positives, because Coccinelle's column
//# calculation does not distinguish between spaces and tabs, so code that
//# is not visually aligned may be considered to be in the same column.
//
// Confidence: Low
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
@r disable braces4@
position p1,p2;
statement S1,S2;
@@
(
if (...) { ... }
|
if (...) S1@p1 S2@p2
)
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
@@
if (p1[0].column == p2[0].column):
cocci.print_main("branch",p1)
cocci.print_secs("after",p2)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
@@
if (p1[0].column == p2[0].column):
msg = "code aligned with following code on line %s" % (p2[0].line)
coccilib.report.print_report(p1[0],msg)
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0
/// Since commit 1c6c69525b40 ("genirq: Reject bogus threaded irq requests")
/// threaded IRQs without a primary handler need to be requested with
/// IRQF_ONESHOT, otherwise the request will fail.
///
/// So pass the IRQF_ONESHOT flag in this case.
///
//
// Confidence: Moderate
// Comments:
// Options: --no-includes
virtual patch
virtual context
virtual org
virtual report
@r1@
expression dev, irq, thread_fn;
position p;
@@
(
request_threaded_irq@p(irq, NULL, thread_fn,
(
IRQF_ONESHOT | ...
|
IRQF_ONESHOT
)
, ...)
|
devm_request_threaded_irq@p(dev, irq, NULL, thread_fn,
(
IRQF_ONESHOT | ...
|
IRQF_ONESHOT
)
, ...)
)
@r2@
expression dev, irq, thread_fn, flags, e;
position p != r1.p;
@@
(
flags = IRQF_ONESHOT | ...
|
flags |= IRQF_ONESHOT | ...
)
... when != flags = e
(
request_threaded_irq@p(irq, NULL, thread_fn, flags, ...);
|
devm_request_threaded_irq@p(dev, irq, NULL, thread_fn, flags, ...);
)
@depends on patch@
expression dev, irq, thread_fn, flags;
position p != {r1.p,r2.p};
@@
(
request_threaded_irq@p(irq, NULL, thread_fn,
(
-0
+IRQF_ONESHOT
|
-flags
+flags | IRQF_ONESHOT
)
, ...)
|
devm_request_threaded_irq@p(dev, irq, NULL, thread_fn,
(
-0
+IRQF_ONESHOT
|
-flags
+flags | IRQF_ONESHOT
)
, ...)
)
@depends on context@
expression dev, irq;
position p != {r1.p,r2.p};
@@
(
*request_threaded_irq@p(irq, NULL, ...)
|
*devm_request_threaded_irq@p(dev, irq, NULL, ...)
)
@match depends on report || org@
expression dev, irq;
position p != {r1.p,r2.p};
@@
(
request_threaded_irq@p(irq, NULL, ...)
|
devm_request_threaded_irq@p(dev, irq, NULL, ...)
)
@script:python depends on org@
p << match.p;
@@
msg = "WARNING: Threaded IRQ with no primary handler requested without IRQF_ONESHOT (unless it is nested IRQ)"
coccilib.org.print_todo(p[0],msg)
@script:python depends on report@
p << match.p;
@@
msg = "WARNING: Threaded IRQ with no primary handler requested without IRQF_ONESHOT (unless it is nested IRQ)"
coccilib.report.print_report(p[0],msg)
@@ -0,0 +1,222 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Check for opencoded min(), max() implementations.
/// Generated patches sometimes require adding a cast to fix compile warning.
/// Warnings/patches scope intentionally limited to a function body.
///
// Confidence: Medium
// Copyright: (C) 2021 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
//
// Keywords: min, max
//
virtual report
virtual org
virtual context
virtual patch
@rmax depends on !patch@
identifier func;
expression x, y;
binary operator cmp = {>, >=};
position p;
@@
func(...)
{
<...
* ((x) cmp@p (y) ? (x) : (y))
...>
}
@rmaxif depends on !patch@
identifier func;
expression x, y;
expression max_val;
binary operator cmp = {>, >=};
position p;
@@
func(...)
{
<...
* if ((x) cmp@p (y)) {
* max_val = (x);
* } else {
* max_val = (y);
* }
...>
}
// Ignore errcode returns.
@errcode@
position p;
identifier func;
expression x;
binary operator cmp = {<, <=};
@@
func(...)
{
<...
return ((x) cmp@p 0 ? (x) : 0);
...>
}
@rmin depends on !patch@
identifier func;
expression x, y;
binary operator cmp = {<, <=};
position p != errcode.p;
@@
func(...)
{
<...
* ((x) cmp@p (y) ? (x) : (y))
...>
}
@rminif depends on !patch@
identifier func;
expression x, y;
expression min_val;
binary operator cmp = {<, <=};
position p;
@@
func(...)
{
<...
* if ((x) cmp@p (y)) {
* min_val = (x);
* } else {
* min_val = (y);
* }
...>
}
@pmax depends on patch@
identifier func;
expression x, y;
binary operator cmp = {>=, >};
@@
func(...)
{
<...
- ((x) cmp (y) ? (x) : (y))
+ max(x, y)
...>
}
@pmaxif depends on patch@
identifier func;
expression x, y;
expression max_val;
binary operator cmp = {>=, >};
@@
func(...)
{
<...
- if ((x) cmp (y)) {
- max_val = x;
- } else {
- max_val = y;
- }
+ max_val = max(x, y);
...>
}
@pmin depends on patch@
identifier func;
expression x, y;
binary operator cmp = {<=, <};
position p != errcode.p;
@@
func(...)
{
<...
- ((x) cmp@p (y) ? (x) : (y))
+ min(x, y)
...>
}
@pminif depends on patch@
identifier func;
expression x, y;
expression min_val;
binary operator cmp = {<=, <};
@@
func(...)
{
<...
- if ((x) cmp (y)) {
- min_val = x;
- } else {
- min_val = y;
- }
+ min_val = min(x, y);
...>
}
@script:python depends on report@
p << rmax.p;
@@
for p0 in p:
coccilib.report.print_report(p0, "WARNING opportunity for max()")
@script:python depends on org@
p << rmax.p;
@@
for p0 in p:
coccilib.org.print_todo(p0, "WARNING opportunity for max()")
@script:python depends on report@
p << rmaxif.p;
@@
for p0 in p:
coccilib.report.print_report(p0, "WARNING opportunity for max()")
@script:python depends on org@
p << rmaxif.p;
@@
for p0 in p:
coccilib.org.print_todo(p0, "WARNING opportunity for max()")
@script:python depends on report@
p << rmin.p;
@@
for p0 in p:
coccilib.report.print_report(p0, "WARNING opportunity for min()")
@script:python depends on org@
p << rmin.p;
@@
for p0 in p:
coccilib.org.print_todo(p0, "WARNING opportunity for min()")
@script:python depends on report@
p << rminif.p;
@@
for p0 in p:
coccilib.report.print_report(p0, "WARNING opportunity for min()")
@script:python depends on org@
p << rminif.p;
@@
for p0 in p:
coccilib.org.print_todo(p0, "WARNING opportunity for min()")
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Catch strings ending in newline with (GE)NL_SET_ERR_MSG*.
///
// Confidence: Very High
// Copyright: (C) 2020 Intel Corporation
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r depends on context || org || report@
expression e;
constant m;
position p;
@@
\(GENL_SET_ERR_MSG\|GENL_SET_ERR_MSG_FMT\|NL_SET_ERR_MSG\|NL_SET_ERR_MSG_MOD\|
NL_SET_ERR_MSG_FMT\|NL_SET_ERR_MSG_FMT_MOD\|NL_SET_ERR_MSG_WEAK\|
NL_SET_ERR_MSG_WEAK_MOD\|NL_SET_ERR_MSG_ATTR_POL\|
NL_SET_ERR_MSG_ATTR_POL_FMT\|NL_SET_ERR_MSG_ATTR\|
NL_SET_ERR_MSG_ATTR_FMT\)(e,m@p,...)
@script:python@
m << r.m;
@@
if not m.endswith("\\n\""):
cocci.include_match(False)
@r1 depends on r@
identifier fname;
expression r.e;
constant r.m;
position r.p;
@@
fname(e,m@p,...)
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@depends on context && r@
identifier r1.fname;
expression r.e;
constant r.m;
@@
* fname(e,m,...)
//----------------------------------------------------------
// For org mode
//----------------------------------------------------------
@script:python depends on org@
fname << r1.fname;
m << r.m;
p << r.p;
@@
if m.endswith("\\n\""):
msg="WARNING avoid newline at end of message in %s" % (fname)
msg_safe=msg.replace("[","@(").replace("]",")")
coccilib.org.print_todo(p[0], msg_safe)
//----------------------------------------------------------
// For report mode
//----------------------------------------------------------
@script:python depends on report@
fname << r1.fname;
m << r.m;
p << r.p;
@@
if m.endswith("\\n\""):
msg="WARNING avoid newline at end of message in %s" % (fname)
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: GPL-2.0-only
/// sizeof when applied to a pointer typed expression gives the size of
/// the pointer
///
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
virtual context
virtual patch
@depends on patch@
expression *x;
expression f;
expression i;
type T;
@@
(
x = <+... sizeof(
- x
+ *x
) ...+>
|
f(...,(T)(x),...,sizeof(
- x
+ *x
),...)
|
f(...,sizeof(
- x
+ *x
),...,(T)(x),...)
|
f(...,(T)(x),...,i*sizeof(
- x
+ *x
),...)
|
f(...,i*sizeof(
- x
+ *x
),...,(T)(x),...)
)
@r depends on !patch@
expression *x;
expression f;
expression i;
position p;
type T;
@@
(
*x = <+... sizeof@p(x) ...+>
|
*f(...,(T)(x),...,sizeof@p(x),...)
|
*f(...,sizeof@p(x),...,(T)(x),...)
|
*f(...,(T)(x),...,i*sizeof@p(x),...)
|
*f(...,i*sizeof@p(x),...,(T)(x),...)
)
@script:python depends on org@
p << r.p;
@@
cocci.print_main("application of sizeof to pointer",p)
@script:python depends on report@
p << r.p;
@@
msg = "ERROR: application of sizeof to pointer"
coccilib.report.print_report(p[0],msg)
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: GPL-2.0
/// Make sure (of/i2c/platform/spi)_device_id tables are NULL terminated
//
// Keywords: of_table i2c_table platform_table
// Confidence: Medium
// Options: --include-headers
virtual patch
virtual context
virtual org
virtual report
@depends on context@
identifier var, arr;
expression E;
@@
(
struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
...,
{
.var = E,
* }
};
|
struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
...,
* { ..., E, ... },
};
)
@depends on patch@
identifier var, arr;
expression E;
@@
(
struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
...,
{
.var = E,
- }
+ },
+ { }
};
|
struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
...,
{ ..., E, ... },
+ { },
};
)
@r depends on org || report@
position p1;
identifier var, arr;
expression E;
@@
(
struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
...,
{
.var = E,
}
@p1
};
|
struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
...,
{ ..., E, ... }
@p1
};
)
@script:python depends on org@
p1 << r.p1;
arr << r.arr;
@@
cocci.print_main(arr,p1)
@script:python depends on report@
p1 << r.p1;
arr << r.arr;
@@
msg = "%s is not NULL terminated at line %s" % (arr, p1[0].line)
coccilib.report.print_report(p1[0],msg)
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Check for constants that are added but are used elsewhere as bitmasks
/// The results should be checked manually to ensure that the nonzero
/// bits in the two constants are actually disjoint.
///
// Confidence: Moderate
// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2013 Gilles Muller, INRIA/LIP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
virtual context
@r@
constant c,c1;
identifier i,i1;
position p;
@@
(
c1 + c - 1
|
c1@i1 +@p c@i
)
@s@
constant r.c, r.c1;
identifier i;
expression e;
@@
(
e | c@i
|
e & c@i
|
e |= c@i
|
e &= c@i
|
e | c1@i
|
e & c1@i
|
e |= c1@i
|
e &= c1@i
)
@depends on s@
position r.p;
constant c1,c2;
@@
* c1 +@p c2
@script:python depends on s && org@
p << r.p;
@@
cocci.print_main("sum of probable bitmasks, consider |",p)
@script:python depends on s && report@
p << r.p;
@@
msg = "WARNING: sum of probable bitmasks, consider |"
coccilib.report.print_report(p[0],msg)
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Use %pe format specifier instead of PTR_ERR() for printing error pointers.
///
/// For printing error pointers (i.e., a pointer for which IS_ERR() is true)
/// %pe will print a symbolic error name (e.g., -EINVAL), opposed to the raw
/// errno (e.g., -22) produced by PTR_ERR().
/// It also makes the code cleaner by saving a redundant call to PTR_ERR().
///
// Confidence: High
// Copyright: (C) 2025 NVIDIA CORPORATION & AFFILIATES.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r@
expression ptr;
constant fmt;
position p;
identifier print_func;
@@
* print_func(..., fmt, ..., PTR_ERR@p(ptr), ...)
@script:python depends on r && report@
p << r.p;
@@
coccilib.report.print_report(p[0], "WARNING: Consider using %pe to print PTR_ERR()")
@script:python depends on r && org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING: Consider using %pe to print PTR_ERR()")
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Remove unneeded variable used to store return value.
///
// Confidence: Moderate
// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments: Comments on code can be deleted if near code that is removed.
// "when strict" can be removed to get more hits, but adds false
// positives
// Options: --no-includes --include-headers
virtual patch
virtual report
virtual context
virtual org
@depends on patch@
type T;
constant C;
identifier ret;
@@
- T ret = C;
... when != ret
when strict
return
- ret
+ C
;
@depends on context@
type T;
constant C;
identifier ret;
@@
* T ret = C;
... when != ret
when strict
* return ret;
@r1 depends on report || org@
type T;
constant C;
identifier ret;
position p1, p2;
@@
T ret@p1 = C;
... when != ret
when strict
return ret@p2;
@script:python depends on report@
p1 << r1.p1;
p2 << r1.p2;
C << r1.C;
ret << r1.ret;
@@
coccilib.report.print_report(p1[0], "Unneeded variable: \"" + ret + "\". Return \"" + C + "\" on line " + p2[0].line)
@script:python depends on org@
p1 << r1.p1;
p2 << r1.p2;
C << r1.C;
ret << r1.ret;
@@
cocci.print_main("unneeded \"" + ret + "\" variable", p1)
cocci.print_sec("return " + C + " here", p2)
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Find usages of:
/// - msecs_to_jiffies(value*1000)
/// - msecs_to_jiffies(value*MSEC_PER_SEC)
///
// Confidence: High
// Copyright: (C) 2024 Easwar Hariharan, Microsoft
// Keywords: secs, seconds, jiffies
// Options: --include-headers
virtual patch
virtual report
virtual context
@pconst depends on patch@ constant C; @@
- msecs_to_jiffies(C * 1000)
+ secs_to_jiffies(C)
@pconstms depends on patch@ constant C; @@
- msecs_to_jiffies(C * MSEC_PER_SEC)
+ secs_to_jiffies(C)
@pexpr depends on patch@ expression E; @@
- msecs_to_jiffies(E * 1000)
+ secs_to_jiffies(E)
@pexprms depends on patch@ expression E; @@
- msecs_to_jiffies(E * MSEC_PER_SEC)
+ secs_to_jiffies(E)
@r depends on report && !patch@
constant C;
expression E;
position p;
@@
(
msecs_to_jiffies(C@p * 1000)
|
msecs_to_jiffies(C@p * MSEC_PER_SEC)
|
msecs_to_jiffies(E@p * 1000)
|
msecs_to_jiffies(E@p * MSEC_PER_SEC)
)
@c depends on context && !patch@
constant C;
expression E;
@@
(
* msecs_to_jiffies(C * 1000)
|
* msecs_to_jiffies(C * MSEC_PER_SEC)
|
* msecs_to_jiffies(E * 1000)
|
* msecs_to_jiffies(E * MSEC_PER_SEC)
)
@script:python depends on report@
p << r.p;
@@
coccilib.report.print_report(p[0], "WARNING opportunity for secs_to_jiffies()")
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Remove unneeded semicolon.
///
// Confidence: Moderate
// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments: Some false positives on empty default cases in switch statements.
// Options: --no-includes --include-headers
virtual patch
virtual report
virtual context
virtual org
@r_default@
position p;
@@
switch (...)
{
default: ...;@p
}
@r_case@
position p;
@@
(
switch (...)
{
case ...:;@p
}
|
switch (...)
{
case ...:...
case ...:;@p
}
|
switch (...)
{
case ...:...
case ...:
case ...:;@p
}
)
@r1@
statement S;
position p1;
position p != {r_default.p, r_case.p};
identifier label;
@@
(
label:;
|
S@p1;@p
)
@script:python@
p << r1.p;
p1 << r1.p1;
@@
if p[0].line != p1[0].line_end:
cocci.include_match(False)
@depends on patch@
position r1.p;
@@
-;@p
@script:python depends on report@
p << r1.p;
@@
coccilib.report.print_report(p[0],"Unneeded semicolon")
@depends on context@
position r1.p;
@@
*;@p
@script:python depends on org@
p << r1.p;
@@
cocci.print_main("Unneeded semicolon",p)
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Check for code that could use struct_size().
///
// Confidence: Medium
// Author: Jacob Keller <jacob.e.keller@intel.com>
// Copyright: (C) 2023 Intel Corporation
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
// the overflow Kunit tests have some code which intentionally does not use
// the macros, so we want to ignore this code when reporting potential
// issues.
@overflow_tests@
identifier f = overflow_size_helpers_test;
@@
f
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@depends on !overflow_tests && context@
expression E1, E2;
identifier m;
@@
(
* (sizeof(*E1) + (E2 * sizeof(*E1->m)))
)
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@depends on !overflow_tests && patch@
expression E1, E2;
identifier m;
@@
(
- (sizeof(*E1) + (E2 * sizeof(*E1->m)))
+ struct_size(E1, m, E2)
)
//----------------------------------------------------------
// For org and report mode
//----------------------------------------------------------
@r depends on !overflow_tests && (org || report)@
expression E1, E2;
identifier m;
position p;
@@
(
(sizeof(*E1)@p + (E2 * sizeof(*E1->m)))
)
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING should use struct_size")
@script:python depends on report@
p << r.p;
@@
msg="WARNING: Use struct_size"
coccilib.report.print_report(p[0], msg)
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Check for opencoded swap() implementation.
///
// Confidence: High
// Copyright: (C) 2021 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
//
// Keywords: swap
//
virtual patch
virtual org
virtual report
virtual context
@rvar depends on !patch@
identifier tmp;
expression a, b;
type T;
position p;
@@
(
* T tmp;
|
* T tmp = 0;
|
* T *tmp = NULL;
)
... when != tmp
* tmp = a;
* a = b;@p
* b = tmp;
... when != tmp
@r depends on !patch@
identifier tmp;
expression a, b;
position p != rvar.p;
@@
* tmp = a;
* a = b;@p
* b = tmp;
@rpvar depends on patch@
identifier tmp;
expression a, b;
type T;
@@
(
- T tmp;
|
- T tmp = 0;
|
- T *tmp = NULL;
)
... when != tmp
- tmp = a;
- a = b;
- b = tmp
+ swap(a, b)
;
... when != tmp
@rp depends on patch@
identifier tmp;
expression a, b;
@@
- tmp = a;
- a = b;
- b = tmp
+ swap(a, b)
;
@depends on patch && (rpvar || rp)@
@@
(
for (...;...;...)
- {
swap(...);
- }
|
while (...)
- {
swap(...);
- }
|
if (...)
- {
swap(...);
- }
)
@script:python depends on report@
p << r.p;
@@
coccilib.report.print_report(p[0], "WARNING opportunity for swap()")
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING opportunity for swap()")
@script:python depends on report@
p << rvar.p;
@@
coccilib.report.print_report(p[0], "WARNING opportunity for swap()")
@script:python depends on org@
p << rvar.p;
@@
coccilib.org.print_todo(p[0], "WARNING opportunity for swap()")
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/// The address of a variable or field is likely always to be non-zero.
///
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual org
virtual report
virtual context
@r@
expression x;
position p;
@@
*\(&x@p == NULL \| &x@p != NULL\)
@script:python depends on org@
p << r.p;
@@
cocci.print_main("test of a variable/field address",p)
@script:python depends on report@
p << r.p;
@@
msg = "ERROR: test of a variable/field address"
coccilib.report.print_report(p[0],msg)
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Please, don't reintroduce uninitialized_var().
///
/// From Documentation/process/deprecated.rst,
/// commit 4b19bec97c88 ("docs: deprecated.rst: Add uninitialized_var()"):
/// For any compiler warnings about uninitialized variables, just add
/// an initializer. Using warning-silencing tricks is dangerous as it
/// papers over real bugs (or can in the future), and suppresses unrelated
/// compiler warnings (e.g. "unused variable"). If the compiler thinks it
/// is uninitialized, either simply initialize the variable or make compiler
/// changes. Keep in mind that in most cases, if an initialization is
/// obviously redundant, the compiler's dead-store elimination pass will make
/// sure there are no needless variable writes.
///
/// Later, commit 3942ea7a10c9 ("deprecated.rst: Remove now removed
/// uninitialized_var") removed this section because all initializations of
/// this kind were cleaned-up from the kernel. This cocci rule checks that
/// the macro is not explicitly or implicitly reintroduced.
///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
//
virtual context
virtual report
virtual org
@r@
identifier var;
type T;
position p;
@@
(
* T var =@p var;
|
* T var =@p *(&(var));
|
* var =@p var
|
* var =@p *(&(var))
)
@script:python depends on report@
p << r.p;
@@
coccilib.report.print_report(p[0], "WARNING this kind of initialization is deprecated")
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING this kind of initialization is deprecated")
@@ -0,0 +1,110 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Use WARN(1,...) rather than printk followed by WARN_ON(1)
///
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@bad1@
position p;
@@
printk(...);
printk@p(...);
WARN_ON(1);
@r1 depends on context || report || org@
position p != bad1.p;
@@
printk@p(...);
*WARN_ON(1);
@script:python depends on org@
p << r1.p;
@@
cocci.print_main("printk + WARN_ON can be just WARN",p)
@script:python depends on report@
p << r1.p;
@@
msg = "SUGGESTION: printk + WARN_ON can be just WARN"
coccilib.report.print_report(p[0],msg)
@ok1 depends on patch@
expression list es;
position p != bad1.p;
@@
-printk@p(
+WARN(1,
es);
-WARN_ON(1);
@depends on patch@
expression list ok1.es;
@@
if (...)
- {
WARN(1,es);
- }
// --------------------------------------------------------------------
@bad2@
position p;
@@
printk(...);
printk@p(...);
WARN_ON_ONCE(1);
@r2 depends on context || report || org@
position p != bad1.p;
@@
printk@p(...);
*WARN_ON_ONCE(1);
@script:python depends on org@
p << r2.p;
@@
cocci.print_main("printk + WARN_ON_ONCE can be just WARN_ONCE",p)
@script:python depends on report@
p << r2.p;
@@
msg = "SUGGESTION: printk + WARN_ON_ONCE can be just WARN_ONCE"
coccilib.report.print_report(p[0],msg)
@ok2 depends on patch@
expression list es;
position p != bad2.p;
@@
-printk@p(
+WARN_ONCE(1,
es);
-WARN_ON_ONCE(1);
@depends on patch@
expression list ok2.es;
@@
if (...)
- {
WARN_ONCE(1,es);
- }
@@ -0,0 +1,239 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Compare pointer-typed values to NULL rather than 0
///
//# This makes an effort to choose between !x and x == NULL. !x is used
//# if it has previously been used with the function used to initialize x.
//# This relies on type information. More type information can be obtained
//# using the option -all_includes and the option -I to specify an
//# include path.
//
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Requires: 1.0.0
// Options:
virtual patch
virtual context
virtual org
virtual report
@initialize:ocaml@
@@
let negtable = Hashtbl.create 101
@depends on patch@
expression *E;
identifier f;
@@
(
(E = f(...)) ==
- 0
+ NULL
|
(E = f(...)) !=
- 0
+ NULL
|
- 0
+ NULL
== (E = f(...))
|
- 0
+ NULL
!= (E = f(...))
)
@t1 depends on !patch@
expression *E;
identifier f;
position p;
@@
(
(E = f(...)) ==
* 0@p
|
(E = f(...)) !=
* 0@p
|
* 0@p
== (E = f(...))
|
* 0@p
!= (E = f(...))
)
@script:python depends on org@
p << t1.p;
@@
coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
@script:python depends on report@
p << t1.p;
@@
coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
// Tests of returned values
@s@
identifier f;
expression E,E1;
@@
E = f(...)
... when != E = E1
!E
@script:ocaml depends on s@
f << s.f;
@@
try let _ = Hashtbl.find negtable f in ()
with Not_found -> Hashtbl.add negtable f ()
@ r disable is_zero,isnt_zero exists @
expression *E;
identifier f;
@@
E = f(...)
...
(E == 0
|E != 0
|0 == E
|0 != E
)
@script:ocaml@
f << r.f;
@@
try let _ = Hashtbl.find negtable f in ()
with Not_found -> include_match false
// This rule may lead to inconsistent path problems, if E is defined in two
// places
@ depends on patch disable is_zero,isnt_zero @
expression *E;
expression E1;
identifier r.f;
@@
E = f(...)
<...
(
- E == 0
+ !E
|
- E != 0
+ E
|
- 0 == E
+ !E
|
- 0 != E
+ E
)
...>
?E = E1
@t2 depends on !patch disable is_zero,isnt_zero @
expression *E;
expression E1;
identifier r.f;
position p1;
position p2;
@@
E = f(...)
<...
(
* E == 0@p1
|
* E != 0@p2
|
* 0@p1 == E
|
* 0@p1 != E
)
...>
?E = E1
@script:python depends on org@
p << t2.p1;
@@
coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0, suggest !E")
@script:python depends on org@
p << t2.p2;
@@
coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
@script:python depends on report@
p << t2.p1;
@@
coccilib.report.print_report(p[0], "WARNING comparing pointer to 0, suggest !E")
@script:python depends on report@
p << t2.p2;
@@
coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
@ depends on patch disable is_zero,isnt_zero @
expression *E;
@@
(
E ==
- 0
+ NULL
|
E !=
- 0
+ NULL
|
- 0
+ NULL
== E
|
- 0
+ NULL
!= E
)
@ t3 depends on !patch disable is_zero,isnt_zero @
expression *E;
position p;
@@
(
* E == 0@p
|
* E != 0@p
|
* 0@p == E
|
* 0@p != E
)
@script:python depends on org@
p << t3.p;
@@
coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
@script:python depends on report@
p << t3.p;
@@
coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
@@ -0,0 +1,283 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// A variable is dereferenced under a NULL test.
/// Even though it is known to be NULL.
///
// Confidence: Moderate
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments: -I ... -all_includes can give more complete results
// Options:
virtual context
virtual org
virtual report
// The following two rules are separate, because both can match a single
// expression in different ways
@pr1 expression@
expression E;
identifier f;
position p1;
@@
(E != NULL && ...) ? <+...E->f@p1...+> : ...
@pr2 expression@
expression E;
identifier f;
position p2;
@@
(
(E != NULL) && ... && <+...E->f@p2...+>
|
(E == NULL) || ... || <+...E->f@p2...+>
|
sizeof(<+...E->f@p2...+>)
)
@ifm@
expression *E;
statement S1,S2;
position p1;
@@
if@p1 ((E == NULL && ...) || ...) S1 else S2
// For org and report modes
@r depends on !context && (org || report) exists@
expression subE <= ifm.E;
expression *ifm.E;
expression E1,E2;
identifier f;
statement S1,S2,S3,S4;
iterator iter;
position p!={pr1.p1,pr2.p2};
position ifm.p1;
@@
if@p1 ((E == NULL && ...) || ...)
{
... when != if (...) S1 else S2
(
iter(subE,...) S4 // no use
|
list_remove_head(E2,subE,...)
|
subE = E1
|
for(subE = E1;...;...) S4
|
subE++
|
++subE
|
--subE
|
subE--
|
&subE
|
E->f@p // bad use
)
... when any
return ...;
}
else S3
@script:python depends on !context && !org && report@
p << r.p;
p1 << ifm.p1;
x << ifm.E;
@@
msg="ERROR: %s is NULL but dereferenced." % (x)
coccilib.report.print_report(p[0], msg)
cocci.include_match(False)
@script:python depends on !context && org && !report@
p << r.p;
p1 << ifm.p1;
x << ifm.E;
@@
msg="ERROR: %s is NULL but dereferenced." % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
cocci.print_main(msg_safe,p)
cocci.include_match(False)
@s depends on !context && (org || report) exists@
expression subE <= ifm.E;
expression *ifm.E;
expression E1,E2;
identifier f;
statement S1,S2,S3,S4;
iterator iter;
position p!={pr1.p1,pr2.p2};
position ifm.p1;
@@
if@p1 ((E == NULL && ...) || ...)
{
... when != if (...) S1 else S2
(
iter(subE,...) S4 // no use
|
list_remove_head(E2,subE,...)
|
subE = E1
|
for(subE = E1;...;...) S4
|
subE++
|
++subE
|
--subE
|
subE--
|
&subE
|
E->f@p // bad use
)
... when any
}
else S3
@script:python depends on !context && !org && report@
p << s.p;
p1 << ifm.p1;
x << ifm.E;
@@
msg="ERROR: %s is NULL but dereferenced." % (x)
coccilib.report.print_report(p[0], msg)
@script:python depends on !context && org && !report@
p << s.p;
p1 << ifm.p1;
x << ifm.E;
@@
msg="ERROR: %s is NULL but dereferenced." % (x)
msg_safe=msg.replace("[","@(").replace("]",")")
cocci.print_main(msg_safe,p)
// For context mode
@depends on context && !org && !report exists@
expression subE <= ifm.E;
expression *ifm.E;
expression E1,E2;
identifier f;
statement S1,S2,S3,S4;
iterator iter;
position p!={pr1.p1,pr2.p2};
position ifm.p1;
@@
if@p1 ((E == NULL && ...) || ...)
{
... when != if (...) S1 else S2
(
iter(subE,...) S4 // no use
|
list_remove_head(E2,subE,...)
|
subE = E1
|
for(subE = E1;...;...) S4
|
subE++
|
++subE
|
--subE
|
subE--
|
&subE
|
* E->f@p // bad use
)
... when any
return ...;
}
else S3
// The following three rules are duplicates of ifm, pr1 and pr2 respectively.
// It is need because the previous rule as already made a "change".
@pr11 depends on context && !org && !report expression@
expression E;
identifier f;
position p1;
@@
(E != NULL && ...) ? <+...E->f@p1...+> : ...
@pr12 depends on context && !org && !report expression@
expression E;
identifier f;
position p2;
@@
(
(E != NULL) && ... && <+...E->f@p2...+>
|
(E == NULL) || ... || <+...E->f@p2...+>
|
sizeof(<+...E->f@p2...+>)
)
@ifm1 depends on context && !org && !report@
expression *E;
statement S1,S2;
position p1;
@@
if@p1 ((E == NULL && ...) || ...) S1 else S2
@depends on context && !org && !report exists@
expression subE <= ifm1.E;
expression *ifm1.E;
expression E1,E2;
identifier f;
statement S1,S2,S3,S4;
iterator iter;
position p!={pr11.p1,pr12.p2};
position ifm1.p1;
@@
if@p1 ((E == NULL && ...) || ...)
{
... when != if (...) S1 else S2
(
iter(subE,...) S4 // no use
|
list_remove_head(E2,subE,...)
|
subE = E1
|
for(subE = E1;...;...) S4
|
subE++
|
++subE
|
--subE
|
subE--
|
&subE
|
* E->f@p // bad use
)
... when any
}
else S3
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0-only
/// The various basic memory allocation functions don't return ERR_PTR
///
// Confidence: High
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@depends on patch@
expression x,E;
@@
x = \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\)(...)
... when != x = E
- IS_ERR(x)
+ !x
@r depends on !patch exists@
expression x,E;
position p1,p2;
@@
*x = \(kmalloc@p1\|kzalloc@p1\|kcalloc@p1\|kmem_cache_alloc@p1\|kmem_cache_zalloc@p1\|kmem_cache_alloc_node@p1\|kmalloc_node@p1\|kzalloc_node@p1\)(...)
... when != x = E
* IS_ERR@p2(x)
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("alloc call",p1)
cocci.print_secs("IS_ERR that should be NULL tests",p2)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "ERROR: allocation function on line %s returns NULL not ERR_PTR on failure" % (p1[0].line)
coccilib.report.print_report(p2[0], msg)
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: GPL-2.0-only
/// This semantic patch looks for kmalloc etc that are not followed by a
/// NULL check. It only gives a report in the case where there is some
/// error handling code later in the function, which may be helpful
/// in determining what the error handling code for the call to kmalloc etc
/// should be.
///
// Confidence: High
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@withtest@
expression x;
position p;
identifier f,fld;
@@
x@p = f(...);
... when != x->fld
\(x == NULL \| x != NULL\)
@fixed depends on context && !org && !report@
expression x,x1;
position p1 != withtest.p;
statement S;
position any withtest.p;
identifier f;
@@
*x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...);
...
*x1@p = f(...);
if (!x1) S
// ------------------------------------------------------------------------
@rfixed depends on (org || report) && !context exists@
expression x,x1;
position p1 != withtest.p;
position p2;
statement S;
position any withtest.p;
identifier f;
@@
x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...);
...
x1@p = f@p2(...);
if (!x1) S
@script:python depends on org@
p1 << rfixed.p1;
p2 << rfixed.p2;
@@
cocci.print_main("alloc call",p1)
cocci.print_secs("possible model",p2)
@script:python depends on report@
p1 << rfixed.p1;
p2 << rfixed.p2;
@@
msg = "alloc with no test, possible model on line %s" % (p2[0].line)
coccilib.report.print_report(p1[0],msg)
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find bit operations that include the same argument more than once
//# One source of false positives is when the argument performs a side
//# effect. Another source of false positives is when a neutral value
//# such as 0 for | is used to indicate no information, to maintain the
//# same structure as other similar expressions
///
// Confidence: Moderate
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r expression@
expression E;
position p;
@@
(
* E@p
& ... & E
|
* E@p
| ... | E
|
* E@p
& ... & !E
|
* E@p
| ... | !E
|
* !E@p
& ... & E
|
* !E@p
| ... | E
)
@script:python depends on org@
p << r.p;
@@
cocci.print_main("duplicated argument to & or |",p)
@script:python depends on report@
p << r.p;
@@
coccilib.report.print_report(p[0],"duplicated argument to & or |")
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Find &&/|| operations that include the same argument more than once
//# A common source of false positives is when the expression, or
//# another expresssion in the same && or || operation, performs a
//# side effect.
///
// Confidence: Moderate
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r expression@
expression E;
position p;
@@
(
E@p || ... || E
|
E@p && ... && E
)
@bad@
expression r.E,e1,e2,fn;
position r.p;
assignment operator op;
@@
(
E@p
&
<+... \(fn(...)\|e1 op e2\|e1++\|e1--\|++e1\|--e1\) ...+>
)
@depends on context && !bad@
expression r.E;
position r.p;
@@
*E@p
@script:python depends on org && !bad@
p << r.p;
@@
cocci.print_main("duplicated argument to && or ||",p)
@script:python depends on report && !bad@
p << r.p;
@@
coccilib.report.print_report(p[0],"duplicated argument to && or ||")
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0-only
/// PTR_ERR should access the value just tested by IS_ERR
//# There can be false positives in the patch case, where it is the call to
//# IS_ERR that is wrong.
///
// Confidence: High
// Copyright: (C) 2012, 2015 Julia Lawall, INRIA.
// Copyright: (C) 2012, 2015 Gilles Muller, INRIA.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@ok1 exists@
expression x,e;
position p;
@@
if (IS_ERR(x=e) || ...) {
<...
PTR_ERR@p(x)
...>
}
@ok2 exists@
expression x,e1,e2;
position p;
@@
if (IS_ERR(x) || ...) {
<...
(
PTR_ERR@p(\(e1 ? e2 : x\|e1 ? x : e2\))
|
PTR_ERR@p(x)
)
...>
}
@r1 depends on patch && !context && !org && !report exists@
expression x,y;
position p != {ok1.p,ok2.p};
@@
if (IS_ERR(x) || ...) {
... when any
when != IS_ERR(...)
(
PTR_ERR(x)
|
PTR_ERR@p(
- y
+ x
)
)
... when any
}
// ----------------------------------------------------------------------------
@r1_context depends on !patch && (context || org || report) exists@
position p != {ok1.p,ok2.p};
expression x, y;
position j0, j1;
@@
if (IS_ERR@j0(x) || ...) {
... when any
when != IS_ERR(...)
(
PTR_ERR(x)
|
PTR_ERR@j1@p(
y
)
)
... when any
}
@r1_disj depends on !patch && (context || org || report) exists@
position p != {ok1.p,ok2.p};
expression x, y;
position r1_context.j0, r1_context.j1;
@@
* if (IS_ERR@j0(x) || ...) {
... when any
when != IS_ERR(...)
* PTR_ERR@j1@p(
y
)
... when any
}
// ----------------------------------------------------------------------------
@script:python r1_org depends on org@
j0 << r1_context.j0;
j1 << r1_context.j1;
@@
msg = "inconsistent IS_ERR and PTR_ERR"
coccilib.org.print_todo(j0[0], msg)
coccilib.org.print_link(j1[0], "")
// ----------------------------------------------------------------------------
@script:python r1_report depends on report@
j0 << r1_context.j0;
j1 << r1_context.j1;
@@
msg = "inconsistent IS_ERR and PTR_ERR on line %s." % (j1[0].line)
coccilib.report.print_report(j0[0], msg)
@@ -0,0 +1,76 @@
// SPDX-License-Identifier: GPL-2.0-only
/// Unsigned expressions cannot be lesser than zero. Presence of
/// comparisons 'unsigned (<|<=|>|>=) 0' often indicates a bug,
/// usually wrong type of variable.
///
/// To reduce number of false positives following tests have been added:
/// - parts of range checks are skipped, eg. "if (u < 0 || u > 15) ...",
/// developers prefer to keep such code,
/// - comparisons "<= 0" and "> 0" are performed only on results of
/// signed functions/macros,
/// - hardcoded list of signed functions/macros with always non-negative
/// result is used to avoid false positives difficult to detect by other ways
///
// Confidence: Average
// Copyright: (C) 2015 Andrzej Hajda, Samsung Electronics Co., Ltd.
// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --all-includes
virtual context
virtual org
virtual report
@r_cmp@
position p;
typedef bool, u8, u16, u32, u64;
{unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long,
size_t, bool, u8, u16, u32, u64} v;
expression e;
@@
\( v = e \| &v \)
...
(\( v@p < 0 \| v@p <= 0 \| v@p >= 0 \| v@p > 0 \))
@r@
position r_cmp.p;
typedef s8, s16, s32, s64;
{char, short, int, long, long long, ssize_t, s8, s16, s32, s64} vs;
expression c, e, v;
identifier f !~ "^(ata_id_queue_depth|btrfs_copy_from_user|dma_map_sg|dma_map_sg_attrs|fls|fls64|gameport_time|get_write_extents|nla_len|ntoh24|of_flat_dt_match|of_get_child_count|uart_circ_chars_pending|[A-Z0-9_]+)$";
@@
(
v = f(...)@vs;
... when != v = e;
* (\( v@p <=@e 0 \| v@p >@e 0 \))
... when any
|
(
(\( v@p < 0 \| v@p <= 0 \)) || ... || (\( v >= c \| v > c \))
|
(\( v >= c \| v > c \)) || ... || (\( v@p < 0 \| v@p <= 0 \))
|
(\( v@p >= 0 \| v@p > 0 \)) && ... && (\( v < c \| v <= c \))
|
((\( v < c \| v <= c \) && ... && \( v@p >= 0 \| v@p > 0 \)))
|
* (\( v@p <@e 0 \| v@p >=@e 0 \))
)
)
@script:python depends on org@
p << r_cmp.p;
e << r.e;
@@
msg = "WARNING: Unsigned expression compared with zero: %s" % (e)
coccilib.org.print_todo(p[0], msg)
@script:python depends on report@
p << r_cmp.p;
e << r.e;
@@
msg = "WARNING: Unsigned expression compared with zero: %s" % (e)
coccilib.report.print_report(p[0], msg)