diff options
Diffstat (limited to 'scripts/coccinelle')
22 files changed, 1627 insertions, 0 deletions
diff --git a/scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci b/scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci new file mode 100644 index 000000000000..7d4771d449c3 --- /dev/null +++ b/scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci @@ -0,0 +1,67 @@ +/// +/// Casting (void *) value returned by kmalloc is useless +/// as mentioned in Documentation/CodingStyle, Chap 14. +/// +// Confidence: High +// Copyright: 2009,2010 Nicolas Palix, DIKU. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Options: -no_includes -include_headers +// +// Keywords: kmalloc, kzalloc, kcalloc +// Version min: < 2.6.12 kmalloc +// Version min: < 2.6.12 kcalloc +// Version min: 2.6.14 kzalloc +// + +virtual context +virtual patch +virtual org +virtual report + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@depends on context@ +type T; +@@ + +* (T *) + \(kmalloc\|kzalloc\|kcalloc\)(...) + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on patch@ +type T; +@@ + +- (T *) + \(kmalloc\|kzalloc\|kcalloc\)(...) + +//---------------------------------------------------------- +// For org and report mode +//---------------------------------------------------------- + +@r depends on org || report@ +type T; +position p; +@@ + + (T@p *)\(kmalloc\|kzalloc\|kcalloc\)(...) + +@script:python depends on org@ +p << r.p; +t << r.T; +@@ + +coccilib.org.print_safe_todo(p[0], t) + +@script:python depends on report@ +p << r.p; +t << r.T; +@@ + +msg="WARNING: casting value returned by k[cmz]alloc to (%s *) is useless." % (t) +coccilib.report.print_report(p[0], msg) diff --git a/scripts/coccinelle/api/alloc/kzalloc-simple.cocci b/scripts/coccinelle/api/alloc/kzalloc-simple.cocci new file mode 100644 index 000000000000..046b9b16f8f9 --- /dev/null +++ b/scripts/coccinelle/api/alloc/kzalloc-simple.cocci @@ -0,0 +1,86 @@ +/// +/// Use kzalloc rather than kmalloc 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. GPLv2. +// Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/rules/kzalloc.html +// 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,E2; +statement S; +@@ + +* x = (T)kmalloc(E1,E2); + if ((x==NULL) || ...) S +* memset((T2)x,0,E1); + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on patch@ +type T, T2; +expression x; +expression E1,E2; +statement S; +@@ + +- x = (T)kmalloc(E1,E2); ++ x = kzalloc(E1,E2); + if ((x==NULL) || ...) S +- memset((T2)x,0,E1); + +//---------------------------------------------------------- +// 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) diff --git a/scripts/coccinelle/api/err_cast.cocci b/scripts/coccinelle/api/err_cast.cocci new file mode 100644 index 000000000000..2ce115000af6 --- /dev/null +++ b/scripts/coccinelle/api/err_cast.cocci @@ -0,0 +1,56 @@ +/// +/// Use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...)) +/// +// Confidence: High +// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2009, 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// 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) diff --git a/scripts/coccinelle/api/kstrdup.cocci b/scripts/coccinelle/api/kstrdup.cocci new file mode 100644 index 000000000000..e0805ad08d39 --- /dev/null +++ b/scripts/coccinelle/api/kstrdup.cocci @@ -0,0 +1,39 @@ +/// Use kstrdup rather than duplicating its implementation +/// +// Confidence: High +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual 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); + +@@ +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); diff --git a/scripts/coccinelle/api/memdup.cocci b/scripts/coccinelle/api/memdup.cocci new file mode 100644 index 000000000000..b5d722077dc1 --- /dev/null +++ b/scripts/coccinelle/api/memdup.cocci @@ -0,0 +1,40 @@ +/// Use kmemdup rather than duplicating its implementation +/// +// Confidence: High +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual patch + +@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); + +@@ +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); diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci new file mode 100644 index 000000000000..72ce012e878a --- /dev/null +++ b/scripts/coccinelle/api/memdup_user.cocci @@ -0,0 +1,35 @@ +/// Use kmemdup_user rather than duplicating its implementation +/// This is a little bit restricted to reduce false positives +/// +// Confidence: High +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual patch + +@@ +expression from,to,size,flag; +position p; +identifier l1,l2; +@@ + +- to = \(kmalloc@p\|kzalloc@p\)(size,flag); ++ 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 +- ...+> +- } diff --git a/scripts/coccinelle/api/resource_size.cocci b/scripts/coccinelle/api/resource_size.cocci new file mode 100644 index 000000000000..1935a58b39d9 --- /dev/null +++ b/scripts/coccinelle/api/resource_size.cocci @@ -0,0 +1,93 @@ +/// +/// Use resource_size function on resource object +/// instead of explicit computation. +/// +// Confidence: High +// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2009, 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// 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) diff --git a/scripts/coccinelle/free/kfree.cocci b/scripts/coccinelle/free/kfree.cocci new file mode 100644 index 000000000000..f9f79d9245ee --- /dev/null +++ b/scripts/coccinelle/free/kfree.cocci @@ -0,0 +1,117 @@ +/// 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 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual org +virtual report + +@free@ +expression E; +position p1; +@@ + +kfree@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 +| + !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) + ... 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,...) +... +( + 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 = "reference preceded by free on line %s" % (p1[0].line) +coccilib.report.print_report(p2[0],msg) diff --git a/scripts/coccinelle/iterators/fen.cocci b/scripts/coccinelle/iterators/fen.cocci new file mode 100644 index 000000000000..77bc108c3f59 --- /dev/null +++ b/scripts/coccinelle/iterators/fen.cocci @@ -0,0 +1,64 @@ +/// These iterators only exit normally when the loop cursor is NULL, so there +/// is no point to call of_node_put on the final value. +/// +// Confidence: High +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual patch + +@@ +iterator name for_each_node_by_name; +expression np,E; +identifier l; +@@ + +for_each_node_by_name(np,...) { + ... when != break; + when != goto l; +} +... when != np = E +- of_node_put(np); + +@@ +iterator name for_each_node_by_type; +expression np,E; +identifier l; +@@ + +for_each_node_by_type(np,...) { + ... when != break; + when != goto l; +} +... when != np = E +- of_node_put(np); + +@@ +iterator name for_each_compatible_node; +expression np,E; +identifier l; +@@ + +for_each_compatible_node(np,...) { + ... when != break; + when != goto l; +} +... when != np = E +- of_node_put(np); + +@@ +iterator name for_each_matching_node; +expression np,E; +identifier l; +@@ + +for_each_matching_node(np,...) { + ... when != break; + when != goto l; +} +... when != np = E +- of_node_put(np); diff --git a/scripts/coccinelle/iterators/itnull.cocci b/scripts/coccinelle/iterators/itnull.cocci new file mode 100644 index 000000000000..baa4297a4ed1 --- /dev/null +++ b/scripts/coccinelle/iterators/itnull.cocci @@ -0,0 +1,58 @@ +/// 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 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual 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 ++ ) +) + ...> }
\ No newline at end of file diff --git a/scripts/coccinelle/iterators/list_entry_update.cocci b/scripts/coccinelle/iterators/list_entry_update.cocci new file mode 100644 index 000000000000..b2967475679b --- /dev/null +++ b/scripts/coccinelle/iterators/list_entry_update.cocci @@ -0,0 +1,62 @@ +/// 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. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual context +virtual org +virtual report + +@r@ +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) diff --git a/scripts/coccinelle/locks/call_kern.cocci b/scripts/coccinelle/locks/call_kern.cocci new file mode 100644 index 000000000000..00af5344a68f --- /dev/null +++ b/scripts/coccinelle/locks/call_kern.cocci @@ -0,0 +1,74 @@ +/// 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) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual patch + +@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@ +identifier gfp.fn; +@@ + +( +read_lock_irq +| +write_lock_irq +| +read_lock_irqsave +| +write_lock_irqsave +| +spin_lock +| +spin_trylock +| +spin_lock_irq +| +spin_lock_irqsave +| +local_irq_disable +) + (...) +... 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(...) + +@depends on locked@ +position gfp.p; +@@ + +- GFP_KERNEL@p ++ GFP_ATOMIC diff --git a/scripts/coccinelle/locks/double_lock.cocci b/scripts/coccinelle/locks/double_lock.cocci new file mode 100644 index 000000000000..63b24e682fad --- /dev/null +++ b/scripts/coccinelle/locks/double_lock.cocci @@ -0,0 +1,92 @@ +/// 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. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// 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) diff --git a/scripts/coccinelle/locks/flags.cocci b/scripts/coccinelle/locks/flags.cocci new file mode 100644 index 000000000000..b4344d838097 --- /dev/null +++ b/scripts/coccinelle/locks/flags.cocci @@ -0,0 +1,80 @@ +/// Find nested lock+irqsave functions that use the same flags variables +/// +// Confidence: High +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual context +virtual org +virtual report + +@r@ +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@ +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 %s." % (p1[0].line) +coccilib.report.print_report(p2[0], msg) diff --git a/scripts/coccinelle/locks/mini_lock.cocci b/scripts/coccinelle/locks/mini_lock.cocci new file mode 100644 index 000000000000..7641a2925434 --- /dev/null +++ b/scripts/coccinelle/locks/mini_lock.cocci @@ -0,0 +1,95 @@ +/// 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 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +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@ +expression E1; +position prelocked.p; +position up != prelocked.p1; +position r!=looped.r; +identifier lock,unlock; +@@ + +lock(E1@p,...); +<+... when != E1 +if (...) { + ... when != E1 + return@r ...; +} +...+> +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) diff --git a/scripts/coccinelle/misc/doubleinit.cocci b/scripts/coccinelle/misc/doubleinit.cocci new file mode 100644 index 000000000000..156b20adb351 --- /dev/null +++ b/scripts/coccinelle/misc/doubleinit.cocci @@ -0,0 +1,53 @@ +/// 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 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// 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 %s, second occurrence %s" % (fld,ps[0].line,pr[0].line) + coccilib.report.print_report(p0[0],msg) diff --git a/scripts/coccinelle/misc/ifcol.cocci b/scripts/coccinelle/misc/ifcol.cocci new file mode 100644 index 000000000000..b7ed91dbeb95 --- /dev/null +++ b/scripts/coccinelle/misc/ifcol.cocci @@ -0,0 +1,48 @@ +/// 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. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// 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) diff --git a/scripts/coccinelle/null/deref_null.cocci b/scripts/coccinelle/null/deref_null.cocci new file mode 100644 index 000000000000..cdac6cfcce92 --- /dev/null +++ b/scripts/coccinelle/null/deref_null.cocci @@ -0,0 +1,282 @@ +/// +/// A variable is dereference under a NULL test. +/// Even though it is know to be NULL. +/// +// Confidence: Moderate +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: -I ... -all_includes can give more complete results +// Options: + +virtual context +virtual org +virtual report + +@ifm@ +expression *E; +statement S1,S2; +position p1; +@@ + +if@p1 ((E == NULL && ...) || ...) S1 else S2 + +// The following two rules are separate, because both can match a single +// expression in different ways +@pr1 expression@ +expression *ifm.E; +identifier f; +position p1; +@@ + + (E != NULL && ...) ? <+...E->f@p1...+> : ... + +@pr2 expression@ +expression *ifm.E; +identifier f; +position p2; +@@ + +( + (E != NULL) && ... && <+...E->f@p2...+> +| + (E == NULL) || ... || <+...E->f@p2...+> +| + sizeof(<+...E->f@p2...+>) +) + +// 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". + +@ifm1@ +expression *E; +statement S1,S2; +position p1; +@@ + +if@p1 ((E == NULL && ...) || ...) S1 else S2 + +@pr11 expression@ +expression *ifm1.E; +identifier f; +position p1; +@@ + + (E != NULL && ...) ? <+...E->f@p1...+> : ... + +@pr12 expression@ +expression *ifm1.E; +identifier f; +position p2; +@@ + +( + (E != NULL) && ... && <+...E->f@p2...+> +| + (E == NULL) || ... || <+...E->f@p2...+> +| + sizeof(<+...E->f@p2...+>) +) + +@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 diff --git a/scripts/coccinelle/null/eno.cocci b/scripts/coccinelle/null/eno.cocci new file mode 100644 index 000000000000..4c9c52b9c413 --- /dev/null +++ b/scripts/coccinelle/null/eno.cocci @@ -0,0 +1,20 @@ +/// The various basic memory allocation functions don't return ERR_PTR +/// +// Confidence: High +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual 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 diff --git a/scripts/coccinelle/null/kmerr.cocci b/scripts/coccinelle/null/kmerr.cocci new file mode 100644 index 000000000000..949bf656c64c --- /dev/null +++ b/scripts/coccinelle/null/kmerr.cocci @@ -0,0 +1,72 @@ +/// 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. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// 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) diff --git a/scripts/coccinelle/tests/doublebitand.cocci b/scripts/coccinelle/tests/doublebitand.cocci new file mode 100644 index 000000000000..9ba73d05a77e --- /dev/null +++ b/scripts/coccinelle/tests/doublebitand.cocci @@ -0,0 +1,54 @@ +/// 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. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// 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 |") diff --git a/scripts/coccinelle/tests/doubletest.cocci b/scripts/coccinelle/tests/doubletest.cocci new file mode 100644 index 000000000000..13a2c0e8a4bf --- /dev/null +++ b/scripts/coccinelle/tests/doubletest.cocci @@ -0,0 +1,40 @@ +/// Find &&/|| operations that include the same argument more than once +//# A common source of false positives is when the argument performs a side +//# effect. +/// +// Confidence: Moderate +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual context +virtual org +virtual report + +@r expression@ +expression E; +position p; +@@ + +( +* 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 ||") |