Merge branch 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6

* 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6: (39 commits)
  Revert "namespace: add source file location exceptions"
  Coccinelle: Add contextual message
  Coccinelle: Fix documentation
  Coccinelle: Find doubled arguments to boolean or bit operators.
  Coccinelle: Find nested lock+irqsave functions that use the same flags variables.
  namespace: add source file location exceptions
  scripts/extract-ikconfig: add support for bzip2, lzma and lzo
  kbuild: check return value of asprintf()
  scripts/namespace.pl: improve to get more correct results
  scripts/namespace.pl: some bug fixes
  scripts/namespace.pl: update file exclusion list
  scripts/namespace.pl: fix wrong source path
  Coccinelle: Use the -no_show_diff option for org and report mode
  Coccinelle: Add a new mode named 'chain'
  Coccinelle: Use new comment format to explain kfree.cocci
  Coccinelle: Improve user information with a new kind of comment
  Coccinelle: Update documentation
  MAINTAINERS: Coccinelle: Update email address
  Documentation/kbuild: modules.txt cleanup
  Documentation/kbuild: major edit of modules.txt sections 5-8
  ...
This commit is contained in:
Linus Torvalds 2010-10-28 16:18:59 -07:00
commit e596c79050
29 changed files with 1591 additions and 470 deletions

View file

@ -333,7 +333,10 @@ static void docsect(char *filename, char *line)
if (*s == '\n')
*s = '\0';
asprintf(&s, "DOC: %s", line);
if (asprintf(&s, "DOC: %s", line) < 0) {
perror("asprintf");
exit(1);
}
consume_symbol(s);
free(s);

View file

@ -16,6 +16,7 @@ if [ "$C" = "1" -o "$C" = "2" ]; then
else
ONLINE=0
FLAGS="-very_quiet"
OPTIONS="-dir $srctree"
fi
if [ ! -x "$SPATCH" ]; then
@ -25,11 +26,13 @@ fi
if [ "$MODE" = "" ] ; then
if [ "$ONLINE" = "0" ] ; then
echo 'You have not explicitly specify the mode to use. Fallback to "report".'
echo 'You have not explicitly specified the mode to use. Using default "chain" mode.'
echo 'All available modes will be tried (in that order): patch, report, context, org'
echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
echo 'Available modes are: report, patch, context, org'
fi
MODE="report"
MODE="chain"
elif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then
FLAGS="$FLAGS -no_show_diff"
fi
if [ "$ONLINE" = "0" ] ; then
@ -44,7 +47,7 @@ coccinelle () {
OPT=`grep "Option" $COCCI | cut -d':' -f2`
# The option '-parse_cocci' can be used to syntaxically check the SmPL files.
# The option '-parse_cocci' can be used to syntactically check the SmPL files.
#
# $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
@ -52,21 +55,44 @@ coccinelle () {
FILE=`echo $COCCI | sed "s|$srctree/||"`
echo "Processing `basename $COCCI` with option(s) \"$OPT\""
echo "Processing `basename $COCCI`"
echo "with option(s) \"$OPT\""
echo ''
echo 'Message example to submit a patch:'
sed -e '/\/\/\//!d' -e 's|^///||' $COCCI
sed -ne 's|^///||p' $COCCI
echo ' The semantic patch that makes this change is available'
if [ "$MODE" = "patch" ] ; then
echo ' The semantic patch that makes this change is available'
elif [ "$MODE" = "report" ] ; then
echo ' The semantic patch that makes this report is available'
elif [ "$MODE" = "context" ] ; then
echo ' The semantic patch that spots this code is available'
elif [ "$MODE" = "org" ] ; then
echo ' The semantic patch that makes this Org report is available'
else
echo ' The semantic patch that makes this output is available'
fi
echo " in $FILE."
echo ''
echo ' More information about semantic patching is available at'
echo ' http://coccinelle.lip6.fr/'
echo ''
$SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT -dir $srctree || exit 1
if [ "`sed -ne 's|^//#||p' $COCCI`" ] ; then
echo 'Semantic patch information:'
sed -ne 's|^//#||p' $COCCI
echo ''
fi
fi
if [ "$MODE" = "chain" ] ; then
$SPATCH -D patch $FLAGS -sp_file $COCCI $OPT $OPTIONS || \
$SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \
$SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || \
$SPATCH -D org $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1
else
$SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
$SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
fi
}

View file

@ -1,5 +1,9 @@
///
/// kzalloc should be used rather than kmalloc followed by memset 0
/// 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.

View file

@ -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);

View file

@ -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);

View file

@ -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
- ...+>
- }

View file

@ -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)

View file

@ -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);

View file

@ -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
+ )
)
...> }

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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:
// 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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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 |")

View file

@ -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 ||")

View file

@ -7,12 +7,10 @@
# The obscure use of the "tr" filter is to work around older versions of
# "grep" that report the byte offset of the line instead of the pattern.
#
# (c) 2009, Dick Streefland <dick@streefland.net>
# (c) 2009,2010 Dick Streefland <dick@streefland.net>
# Licensed under the terms of the GNU General Public License.
# ----------------------------------------------------------------------
gz1='\037\213\010'
gz2='01'
cf1='IKCFG_ST\037\213\010'
cf2='0123456789'
@ -21,11 +19,25 @@ dump_config()
if pos=`tr "$cf1\n$cf2" "\n$cf2=" < "$1" | grep -abo "^$cf2"`
then
pos=${pos%%:*}
tail -c+$(($pos+8)) "$1" | zcat -q
exit 0
tail -c+$(($pos+8)) "$1" | zcat > $tmp1 2> /dev/null
if [ $? != 1 ]
then # exit status must be 0 or 2 (trailing garbage warning)
cat $tmp1
exit 0
fi
fi
}
try_decompress()
{
for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"`
do
pos=${pos%%:*}
tail -c+$pos "$img" | $3 > $tmp2 2> /dev/null
dump_config $tmp2
done
}
# Check invocation:
me=${0##*/}
img=$1
@ -35,18 +47,19 @@ then
exit 2
fi
# Prepare temp files:
tmp1=/tmp/ikconfig$$.1
tmp2=/tmp/ikconfig$$.2
trap "rm -f $tmp1 $tmp2" 0
# Initial attempt for uncompressed images or objects:
dump_config "$img"
# That didn't work, so decompress and try again:
tmp=/tmp/ikconfig$$
trap "rm -f $tmp" 0
for pos in `tr "$gz1\n$gz2" "\n$gz2=" < "$img" | grep -abo "^$gz2"`
do
pos=${pos%%:*}
tail -c+$pos "$img" | zcat 2> /dev/null > $tmp
dump_config $tmp
done
# That didn't work, so retry after decompression.
try_decompress '\037\213\010' xy gunzip
try_decompress 'BZh' xy bunzip2
try_decompress '\135\0\0\0' xxx unlzma
try_decompress '\211\114\132' xy 'lzop -d'
# Bail out:
echo "$me: Cannot find kernel config." >&2

View file

@ -84,6 +84,64 @@ my %ksymtab = (); # names that appear in __ksymtab_
my %ref = (); # $ref{$name} exists if there is a true external reference to $name
my %export = (); # $export{$name} exists if there is an EXPORT_... of $name
my %nmexception = (
'fs/ext3/bitmap' => 1,
'fs/ext4/bitmap' => 1,
'arch/x86/lib/thunk_32' => 1,
'arch/x86/lib/cmpxchg' => 1,
'arch/x86/vdso/vdso32/note' => 1,
'lib/irq_regs' => 1,
'usr/initramfs_data' => 1,
'drivers/scsi/aic94xx/aic94xx_dump' => 1,
'drivers/scsi/libsas/sas_dump' => 1,
'lib/dec_and_lock' => 1,
'drivers/ide/ide-probe-mini' => 1,
'usr/initramfs_data' => 1,
'drivers/acpi/acpia/exdump' => 1,
'drivers/acpi/acpia/rsdump' => 1,
'drivers/acpi/acpia/nsdumpdv' => 1,
'drivers/acpi/acpia/nsdump' => 1,
'arch/ia64/sn/kernel/sn2/io' => 1,
'arch/ia64/kernel/gate-data' => 1,
'security/capability' => 1,
'fs/ntfs/sysctl' => 1,
'fs/jfs/jfs_debug' => 1,
);
my %nameexception = (
'mod_use_count_' => 1,
'__initramfs_end' => 1,
'__initramfs_start' => 1,
'_einittext' => 1,
'_sinittext' => 1,
'kallsyms_names' => 1,
'kallsyms_num_syms' => 1,
'kallsyms_addresses'=> 1,
'__this_module' => 1,
'_etext' => 1,
'_edata' => 1,
'_end' => 1,
'__bss_start' => 1,
'_text' => 1,
'_stext' => 1,
'__gp' => 1,
'ia64_unw_start' => 1,
'ia64_unw_end' => 1,
'__init_begin' => 1,
'__init_end' => 1,
'__bss_stop' => 1,
'__nosave_begin' => 1,
'__nosave_end' => 1,
'pg0' => 1,
'vdso_enabled' => 1,
'__stack_chk_fail' => 1,
'VDSO32_PRELINK' => 1,
'VDSO32_vsyscall' => 1,
'VDSO32_rt_sigreturn'=>1,
'VDSO32_sigreturn' => 1,
);
&find(\&linux_objects, '.'); # find the objects and do_nm on them
&list_multiply_defined();
&resolve_external_references();
@ -105,7 +163,8 @@ sub linux_objects
if (/.*\.o$/ &&
! (
m:/built-in.o$:
|| m:arch/x86/kernel/vsyscall-syms.o$:
|| m:arch/x86/vdso/:
|| m:arch/x86/boot/:
|| m:arch/ia64/ia32/ia32.o$:
|| m:arch/ia64/kernel/gate-syms.o$:
|| m:arch/ia64/lib/__divdi3.o$:
@ -148,6 +207,7 @@ sub linux_objects
|| m:^.*/\.tmp_:
|| m:^\.tmp_:
|| m:/vmlinux-obj.o$:
|| m:^tools/:
)
) {
do_nm($basename, $_);
@ -167,11 +227,11 @@ sub do_nm
printf STDERR "$fullname is not an object file\n";
return;
}
($source = $fullname) =~ s/\.o$//;
if (-e "$objtree$source.c" || -e "$objtree$source.S") {
$source = "$objtree$source";
($source = $basename) =~ s/\.o$//;
if (-e "$source.c" || -e "$source.S") {
$source = "$objtree$File::Find::dir/$source";
} else {
$source = "$srctree$source";
$source = "$srctree$File::Find::dir/$source";
}
if (! -e "$source.c" && ! -e "$source.S") {
# No obvious source, exclude the object if it is conglomerate
@ -214,6 +274,7 @@ sub do_nm
# T global label/procedure
# U external reference
# W weak external reference to text that has been resolved
# V similar to W, but the value of the weak symbol becomes zero with no error.
# a assembler equate
# b static variable, uninitialised
# d static variable, initialised
@ -222,8 +283,9 @@ sub do_nm
# s static variable, uninitialised, small bss
# t static label/procedures
# w weak external reference to text that has not been resolved
# v similar to w
# ? undefined type, used a lot by modules
if ($type !~ /^[ABCDGRSTUWabdgrstw?]$/) {
if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) {
printf STDERR "nm output for $fullname contains unknown type '$_'\n";
}
elsif ($name =~ /\./) {
@ -234,7 +296,7 @@ sub do_nm
# binutils keeps changing the type for exported symbols, force it to R
$type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
$name =~ s/_R[a-f0-9]{8}$//; # module versions adds this
if ($type =~ /[ABCDGRSTW]/ &&
if ($type =~ /[ABCDGRSTWV]/ &&
$name ne 'init_module' &&
$name ne 'cleanup_module' &&
$name ne 'Using_Versions' &&
@ -270,27 +332,9 @@ sub do_nm
close($nmdata);
if ($#nmdata < 0) {
if (
$fullname ne "lib/brlock.o"
&& $fullname ne "lib/dec_and_lock.o"
&& $fullname ne "fs/xfs/xfs_macros.o"
&& $fullname ne "drivers/ide/ide-probe-mini.o"
&& $fullname ne "usr/initramfs_data.o"
&& $fullname ne "drivers/acpi/executer/exdump.o"
&& $fullname ne "drivers/acpi/resources/rsdump.o"
&& $fullname ne "drivers/acpi/namespace/nsdumpdv.o"
&& $fullname ne "drivers/acpi/namespace/nsdump.o"
&& $fullname ne "arch/ia64/sn/kernel/sn2/io.o"
&& $fullname ne "arch/ia64/kernel/gate-data.o"
&& $fullname ne "drivers/ieee1394/oui.o"
&& $fullname ne "security/capability.o"
&& $fullname ne "sound/core/wrappers.o"
&& $fullname ne "fs/ntfs/sysctl.o"
&& $fullname ne "fs/jfs/jfs_debug.o"
) {
printf "No nm data for $fullname\n";
}
return;
printf "No nm data for $fullname\n"
unless $nmexception{$fullname};
return;
}
$nmdata{$fullname} = \@nmdata;
}
@ -319,18 +363,14 @@ sub list_multiply_defined
foreach my $name (keys(%def)) {
if ($#{$def{$name}} > 0) {
# Special case for cond_syscall
if ($#{$def{$name}} == 1 && $name =~ /^sys_/ &&
($def{$name}[0] eq "kernel/sys.o" ||
$def{$name}[1] eq "kernel/sys.o")) {
&drop_def("kernel/sys.o", $name);
next;
}
# Special case for i386 entry code
if ($#{$def{$name}} == 1 && $name =~ /^__kernel_/ &&
$def{$name}[0] eq "arch/x86/kernel/vsyscall-int80_32.o" &&
$def{$name}[1] eq "arch/x86/kernel/vsyscall-sysenter_32.o") {
&drop_def("arch/x86/kernel/vsyscall-sysenter_32.o", $name);
next;
if ($#{$def{$name}} == 1 &&
($name =~ /^sys_/ || $name =~ /^compat_sys_/ ||
$name =~ /^sys32_/)) {
if($def{$name}[0] eq "kernel/sys_ni.o" ||
$def{$name}[1] eq "kernel/sys_ni.o") {
&drop_def("kernel/sys_ni.o", $name);
next;
}
}
printf "$name is multiply defined in :-\n";
@ -372,31 +412,7 @@ sub resolve_external_references
$ref{$name} = ""
}
}
elsif ( $name ne "mod_use_count_"
&& $name ne "__initramfs_end"
&& $name ne "__initramfs_start"
&& $name ne "_einittext"
&& $name ne "_sinittext"
&& $name ne "kallsyms_names"
&& $name ne "kallsyms_num_syms"
&& $name ne "kallsyms_addresses"
&& $name ne "__this_module"
&& $name ne "_etext"
&& $name ne "_edata"
&& $name ne "_end"
&& $name ne "__bss_start"
&& $name ne "_text"
&& $name ne "_stext"
&& $name ne "__gp"
&& $name ne "ia64_unw_start"
&& $name ne "ia64_unw_end"
&& $name ne "__init_begin"
&& $name ne "__init_end"
&& $name ne "__bss_stop"
&& $name ne "__nosave_begin"
&& $name ne "__nosave_end"
&& $name ne "pg0"
&& $name ne "__module_text_address"
elsif ( ! $nameexception{$name}
&& $name !~ /^__sched_text_/
&& $name !~ /^__start_/
&& $name !~ /^__end_/
@ -407,7 +423,6 @@ sub resolve_external_references
&& $name !~ /^__.*per_cpu_end/
&& $name !~ /^__alt_instructions/
&& $name !~ /^__setup_/
&& $name !~ /^jiffies/
&& $name !~ /^__mod_timer/
&& $name !~ /^__mod_page_state/
&& $name !~ /^init_module/