From 13ffb1de640e0cb82bf419e26666d3c48275a69c Mon Sep 17 00:00:00 2001 From: Boris Faure Date: Wed, 8 Jun 2022 23:57:36 +0200 Subject: [PATCH] add scripts/coccinelle --- scripts/coccinelle/andconst.cocci | 18 ++++ scripts/coccinelle/badzero.cocci | 51 ++++++++++++ scripts/coccinelle/coccicheck.sh | 29 +++++++ scripts/coccinelle/continue.cocci | 17 ++++ scripts/coccinelle/free_stack.cocci | 15 ++++ scripts/coccinelle/mutex.cocci | 38 +++++++++ scripts/coccinelle/notand.cocci | 14 ++++ scripts/coccinelle/notnull.cocci | 104 ++++++++++++++++++++++++ scripts/coccinelle/null_ref.cocci | 66 +++++++++++++++ scripts/coccinelle/unused.cocci | 26 ++++++ scripts/coccinelle/use_after_iter.cocci | 69 ++++++++++++++++ 11 files changed, 447 insertions(+) create mode 100644 scripts/coccinelle/andconst.cocci create mode 100644 scripts/coccinelle/badzero.cocci create mode 100755 scripts/coccinelle/coccicheck.sh create mode 100644 scripts/coccinelle/continue.cocci create mode 100644 scripts/coccinelle/free_stack.cocci create mode 100644 scripts/coccinelle/mutex.cocci create mode 100644 scripts/coccinelle/notand.cocci create mode 100644 scripts/coccinelle/notnull.cocci create mode 100644 scripts/coccinelle/null_ref.cocci create mode 100644 scripts/coccinelle/unused.cocci create mode 100644 scripts/coccinelle/use_after_iter.cocci diff --git a/scripts/coccinelle/andconst.cocci b/scripts/coccinelle/andconst.cocci new file mode 100644 index 00000000..88005ab6 --- /dev/null +++ b/scripts/coccinelle/andconst.cocci @@ -0,0 +1,18 @@ +// Two comparisons of the same expression to different constants, +// connected by a conjunction +// Confidence: Moderate +// Copyright: (C) Diego Liziero +// URL: https://coccinelle.gitlabpages.inria.fr/website/rules/andconst.html +// Options: + +@@ identifier i; constant C1,C2; @@ +( +- i == C1 && i == C2 ++ i == C1 || i == C2 +) + +@@ identifier i; constant C1,C2; @@ +( +- i != C1 || i != C2 ++ i != C1 && i != C2 +) diff --git a/scripts/coccinelle/badzero.cocci b/scripts/coccinelle/badzero.cocci new file mode 100644 index 00000000..bc27dfd6 --- /dev/null +++ b/scripts/coccinelle/badzero.cocci @@ -0,0 +1,51 @@ +// A pointer should not be compared to zero +// +// Confidence: High +// Copyright: (C) Gilles Muller, Julia Lawall, EMN, INRIA, DIKU. GPLv2. +// URL: https://coccinelle.gitlabpages.inria.fr/website/rules/badzero.html +// Options: + +@ disable is_zero,isnt_zero @ +expression *E; +expression E1,f; +@@ + +E = f(...) +<... +( +- E == 0 ++ !E +| +- E != 0 ++ E +| +- 0 == E ++ !E +| +- 0 != E ++ E +) +...> +?E = E1 + +@ disable is_zero,isnt_zero @ +expression *E; +@@ + +( + E == +- 0 ++ NULL +| + E != +- 0 ++ NULL +| +- 0 ++ NULL + == E +| +- 0 ++ NULL + != E +) diff --git a/scripts/coccinelle/coccicheck.sh b/scripts/coccinelle/coccicheck.sh new file mode 100755 index 00000000..8016b1f3 --- /dev/null +++ b/scripts/coccinelle/coccicheck.sh @@ -0,0 +1,29 @@ +#!/bin/sh +set -eu + +DIR="src/bin" +COCCI_FILES=" +andconst.cocci +badzero.cocci +continue.cocci +free_stack.cocci +mutex.cocci +notand.cocci +notnull.cocci +null_ref.cocci +unused.cocci +use_after_iter.cocci +" + +HAS_ERROR=0 +for f in $COCCI_FILES; do + CMD="spatch --timeout 200 --very-quiet --cocci-file scripts/coccinelle/$f --include-headers --dir $DIR" + #CMD="spatch --very-quiet --cocci-file scripts/coccinelle/$f --dir $DIR -allow_inconsistent_paths" + OUT=$($CMD) + echo "$CMD" + if [ -n "$OUT" ]; then + echo "$OUT" + HAS_ERROR=1 + fi +done +exit $HAS_ERROR diff --git a/scripts/coccinelle/continue.cocci b/scripts/coccinelle/continue.cocci new file mode 100644 index 00000000..bc0da141 --- /dev/null +++ b/scripts/coccinelle/continue.cocci @@ -0,0 +1,17 @@ +// Continue at the end of a for loop has no purpose +// +// Confidence: Moderate +// Copyright: (C) Gilles Muller, Julia Lawall, EMN, INRIA, DIKU. GPLv2. +// URL: https://coccinelle.gitlabpages.inria.fr/website/rules/continue.html +// Options: + +@@ +@@ + +for (...;...;...) { + ... + if (...) { + ... +- continue; + } +} diff --git a/scripts/coccinelle/free_stack.cocci b/scripts/coccinelle/free_stack.cocci new file mode 100644 index 00000000..3a384ef8 --- /dev/null +++ b/scripts/coccinelle/free_stack.cocci @@ -0,0 +1,15 @@ +// For fun, but gcc actually detects those by itself +@@ +type T; +identifier K; +expression E; +@@ +( +( +T K; +| +T K = E; +) +... +- free(&K); +) diff --git a/scripts/coccinelle/mutex.cocci b/scripts/coccinelle/mutex.cocci new file mode 100644 index 00000000..85538a27 --- /dev/null +++ b/scripts/coccinelle/mutex.cocci @@ -0,0 +1,38 @@ +// A mutex_lock is not matched by a mutex_unlock before an error return/goto. +@@ +expression l; +identifier LOCK =~ "^.*_lock$"; +identifier UN =~ "^.*_unlock$"; +@@ + +LOCK(l); +... when != UN(l) + when any + when strict +( +{ ... when != UN(l) ++ todo_add_unlock(l); + return ...; +} +| +UN(l); +) + + +// unlock from not locked code +//@@ +//expression E; +//identifier LOCK =~ "^.*_lock$"; +//identifier UN =~ "^.*_unlock$"; +//@@ +//... when != LOCK(E) +//( +//if (...) { +//+add_LOCK(E); +//... when != LOCK(E) +// UN(E); +// return ...; +//} +//| +//UN(E) +//) diff --git a/scripts/coccinelle/notand.cocci b/scripts/coccinelle/notand.cocci new file mode 100644 index 00000000..399cc2ab --- /dev/null +++ b/scripts/coccinelle/notand.cocci @@ -0,0 +1,14 @@ +// !x&y combines boolean negation with bitwise and +// +// Confidence: High +// Copyright: (C) Gilles Muller, Julia Lawall, EMN, INRIA, DIKU. GPLv2. +// URL: https://coccinelle.gitlabpages.inria.fr/website/rules/notand.html +// Options: + +@@ expression E; constant C; @@ +( + !E & !C +| +- !E & C ++ !(E & C) +) diff --git a/scripts/coccinelle/notnull.cocci b/scripts/coccinelle/notnull.cocci new file mode 100644 index 00000000..3ff4da62 --- /dev/null +++ b/scripts/coccinelle/notnull.cocci @@ -0,0 +1,104 @@ +// this detects NULL tests that can only be reached when the value is known +// not to be NULL +// +// Confidence: High +// Copyright: (C) Gilles Muller, Julia Lawall, EMN, INRIA, DIKU. GPLv2. +// URL: https://coccinelle.gitlabpages.inria.fr/website/rules/notnull.html +// Options: + +@r exists@ +local idexpression x; +expression E; +position p1,p2; +@@ + +if (x@p1 == NULL || ...) { ... when forall + return ...; } +... when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\) + when != &x +( +x@p2 == NULL +| +x@p2 != NULL +) + +// another path to the test that is not through p1? + +@s exists@ +local idexpression r.x; +position r.p1,r.p2; +@@ + +... when != x@p1 +( +x@p2 == NULL +| +x@p2 != NULL +) + +// another path to the test from p1? + +@t exists@ +local idexpression x; +position r.p1,r.p2; +@@ + +if (x@p1 == NULL || ...) { ... x@p2 ... when any + return ...; } + +// another path to the test containing an assignment? + +@u exists@ +local idexpression x; +expression E; +position r.p1,r.p2; +@@ + +if (x@p1 == NULL || ...) { ... when forall + return ...; } + ... + \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) + ... when != x@p1 + when any +( +x@p2 == NULL +| +x@p2 != NULL +) + +@fix depends on !s && !t && !u@ +position r.p2; +expression x,E; +statement S1,S2; +@@ + +( +- if ((x@p2 != NULL) || ...) + S1 +| +- if ((x@p2 != NULL) || ...) + S1 +- else S2 +| +- (x@p2 != NULL) && E ++ E +| +- (x@p2 == NULL) || E ++ E +| +- if ((x@p2 == NULL) && ...) S1 +| +- if ((x@p2 == NULL) && ...) S1 else + S2 +| +- BUG_ON(x@p2 == NULL); +) + +@script:python depends on !s && !t && !u && !fix@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("",p1) +cocci.print_secs("retest",p2) + diff --git a/scripts/coccinelle/null_ref.cocci b/scripts/coccinelle/null_ref.cocci new file mode 100644 index 00000000..8c0ee741 --- /dev/null +++ b/scripts/coccinelle/null_ref.cocci @@ -0,0 +1,66 @@ +// find cases where a pointer is dereferenced and then compared to NULL +// +// Confidence: High +// Copyright: (C) Gilles Muller, Julia Lawall, EMN, INRIA, DIKU. GPLv2. +// URL: https://coccinelle.gitlabpages.inria.fr/website/rules/null_ref.html +// Options: + +@match exists@ +expression x, E,E1; +identifier fld; +position p1,p2; +@@ + +( +x = E; +... when != \(x = E1\|&x\) +x@p2 == NULL +... when any +| +x = E +... when != \(x = E1\|&x\) +x@p2 == NULL +... when any +| +x != NULL && (<+...x->fld...+>) +| +x == NULL || (<+...x->fld...+>) +| +x != NULL ? (<+...x->fld...+>) : E +| +x@p1->fld +... when != \(x = E\|&x\) +x@p2 == NULL +... when any +) + +@other_match exists@ +expression match.x, E1, E2; +position match.p1,match.p2; +@@ + +( +x = E1 +| +x +) +... when != \(x = E2\|&x\) + when != x@p1 +x@p2 + +@other_match1 exists@ +expression match.x, E2; +position match.p1,match.p2; +@@ + +... when != \(x = E2\|&x\) + when != x@p1 +x@p2 + +@ script:python depends on !other_match && !other_match1@ +p1 << match.p1; +p2 << match.p2; +@@ + +cocci.print_main("",p1) +cocci.print_sec("NULL test",p2) diff --git a/scripts/coccinelle/unused.cocci b/scripts/coccinelle/unused.cocci new file mode 100644 index 00000000..132eede8 --- /dev/null +++ b/scripts/coccinelle/unused.cocci @@ -0,0 +1,26 @@ +// A variable is only initialized to a constant and is never used otherwise +// +// Confidence: High +// Copyright: (C) Gilles Muller, Julia Lawall, EMN, INRIA, DIKU. GPLv2. +// URL: https://coccinelle.gitlabpages.inria.fr/website/rules/unused.html +// Options: + +@e@ +identifier i; +position p; +type T; +@@ + +extern T i@p; + +@@ +type T; +identifier i; +constant C; +position p != e.p; +@@ + +- T i@p; + <+... when != i +- i = C; + ...+> diff --git a/scripts/coccinelle/use_after_iter.cocci b/scripts/coccinelle/use_after_iter.cocci new file mode 100644 index 00000000..9078ed26 --- /dev/null +++ b/scripts/coccinelle/use_after_iter.cocci @@ -0,0 +1,69 @@ +@@ +identifier Iter, Next, M, Data; +iterator name EINA_LIST_FOREACH; +iterator name EINA_LIST_REVERSE_FOREACH; +iterator name EINA_LIST_FREE; +iterator name EINA_INLIST_FOREACH; +iterator name EINA_INLIST_FOREACH_SAFE; +iterator name EINA_ITERATOR_FOREACH; +iterator name EINA_ARRAY_ITER_NEXT; +expression E,x, i; +position p1,p2; +statement S; +@@ + +( +EINA_INLIST_FOREACH(x, Data@p1) { ... when != break; + when forall + when strict +} +| +EINA_INLIST_FOREACH_SAFE(x, Data@p1) { ... when != break; + when forall + when strict +} +| +EINA_LIST_FOREACH(x, Iter@p1, Data@p1) { ... when != break; + when forall + when strict +} +| +EINA_LIST_REVERSE_FOREACH(x, Iter@p1, Data@p1) { ... when != break; + when forall + when strict +} +| +EINA_LIST_FREE(x, Data@p1) { ... when != break; + when forall + when strict +} +| +EINA_ARRAY_ITER_NEXT(x, i, Data@p1, Iter@p1) { ... when != break; + when forall + when strict +} +) +... +( +EINA_INLIST_FOREACH(x, Data) S +| +EINA_INLIST_FOREACH_SAFE(x, Data) S +| +EINA_LIST_FREE(x, Data) S +| +EINA_LIST_FOREACH(x, Iter, Data) S +| +EINA_LIST_REVERSE_FOREACH(x, Iter, Data) S +| +EINA_ARRAY_ITER_NEXT(x, i, Data, Iter) S +| +- *Next@p2 +| +- *Iter@p2 +| +- *Data@p2 +| +- Data->M@p2 +| +- E = Data@p2 +)