Browse Source

dist: tools: introduce coccinelle static testing

master
Kaspar Schleiser 6 years ago
parent
commit
9acc5282af
  1. 1
      dist/tools/ci/build_and_test.sh
  2. 78
      dist/tools/coccinelle/check.sh
  3. 51
      dist/tools/coccinelle/force/badzero.cocci
  4. 17
      dist/tools/coccinelle/force/continue.cocci
  5. 25
      dist/tools/coccinelle/force/static.cocci
  6. 1
      dist/tools/coccinelle/include/riot-standard.h
  7. 103
      dist/tools/coccinelle/warn/notnull.cocci

1
dist/tools/ci/build_and_test.sh vendored

@ -89,6 +89,7 @@ then
run ./dist/tools/externc/check.sh
run ./dist/tools/cppcheck/check.sh
run ./dist/tools/pr_check/pr_check.sh ${CI_BASE_BRANCH}
run ./dist/tools/coccinelle/check.sh
exit $RESULT
fi

78
dist/tools/coccinelle/check.sh vendored

@ -0,0 +1,78 @@
#!/bin/sh
# Copyright 2017 Kaspar Schleiser <kaspar@schleiser.de>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
: ${RIOTBASE:=$(pwd)}
. ${RIOTBASE}/dist/tools/ci/changed_files.sh
EXIT_CODE=0
filter() {
if [ $COCCINELLE_QUIET -eq 0 ]; then
cat
else
grep '^---' | cut -f 2 -d ' '
fi
}
indent() {
sed 's/^/ /g'
}
coccinelle_checkone() {
OUT="$(spatch --very-quiet \
--macro-file-builtins ${RIOTBASE}/dist/tools/coccinelle/include/riot-standard.h \
--sp-file $patch ${FILES} | filter)"
if [ -n "$OUT" ]; then
if [ $COCCINELLE_QUIET -eq 1 ]; then
echo "$patch:"
echo "$OUT" | indent
if [ COCCINELLE_WARNONLY -eq 0 ]; then
EXIT_CODE=1
fi
else
echo "$OUT"
fi
fi
}
coccinelle_checkall() {
local dir="$1"
local warn="${2:-0}"
[ -d "$dir" ] || {
echo "$0: coccinelle_checkall(): $dir doesn't exist!"
exit 1
}
for patch in $dir/*; do
coccinelle_checkone $patch
done
}
: ${FILES:=$(FILEREGEX='\.c$' changed_files)}
if [ -z "${FILES}" ]; then
exit
fi
: ${COCCINELLE_QUIET:=0}
if [ -z "$*" ]; then
coccinelle_checkall ${RIOTBASE}/dist/tools/coccinelle/force
COCCINELLE_WARNONLY=1 \
coccinelle_checkall ${RIOTBASE}/dist/tools/coccinelle/warn
else
for patch in "$@"; do
coccinelle_checkone "$patch"
done
fi
exit $EXIT_CODE

51
dist/tools/coccinelle/force/badzero.cocci vendored

@ -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: http://coccinelle.lip6.fr/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
)

17
dist/tools/coccinelle/force/continue.cocci vendored

@ -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: http://coccinelle.lip6.fr/rules/continue.html
// Options:
@@
@@
for (...;...;...) {
...
if (...) {
...
- continue;
}
}

25
dist/tools/coccinelle/force/static.cocci vendored

@ -0,0 +1,25 @@
// remove unused static property of function-local static variable
// (from Julia Lawall, see https://lists.riot-os.org/pipermail/devel/2017-May/005133.html)
@bad exists@
position p;
identifier x;
type T;
@@
static T x@p;
...
x = <+...x...+>
@@
identifier x;
expression e;
type T;
position p != bad.p;
@@
-static
T x@p;
... when != x
when strict
?x = e;

1
dist/tools/coccinelle/include/riot-standard.h vendored

@ -0,0 +1 @@
#define LL_SEARCH_SCALAR(pkt, tcp, type, GNRC_NETTYPE_TCP) tcp = XXX

103
dist/tools/coccinelle/warn/notnull.cocci vendored

@ -0,0 +1,103 @@
// 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: http://coccinelle.lip6.fr/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)
Loading…
Cancel
Save