permit multiline comments and strings in macros
[bpt/coccinelle.git] / demos / unsigned.txt
1 From 12o3l@tiscali.nl Fri Apr 18 18:13:39 2008
2 Date: Fri, 18 Apr 2008 18:15:06 +0200
3 From: Roel Kluin <12o3l@tiscali.nl>
4 To: kernel-janitors@vger.kernel.org, kernelnewbies-bounce@nl.linux.org
5 Subject: script to find incorrect tests on unsigneds
6
7 A bash script to find incorrect tests on unsigned values. for instance:
8
9 unsigned int i;
10 ...
11 i = neg_ret_function();
12 ...
13 if (i < 0) ...
14
15 #!/bin/bash
16 # (c) roel kluin 2008 GPL v2
17 #
18 # TODO: make this working also for
19 # ... $unsigned_var == $signed_var ...
20 # ... $unsigned_var == \(-POSITIVE_DEF\|NEGATIVE_DEF\) ...
21 # ... ( $unsigned_var [+*/%^&~-]?= ... ) < 0 ...
22
23 # a number
24 int="[0-9]"
25 hex="[a-f0-9]"
26 hEx="[A-Fa-f0-9]"
27 HEX="[A-F0-9]"
28 upp="[A-Z]"
29 up_="[A-Z_]"
30 low="[a-z0-9]"
31 lo_="[a-z0-9_]"
32 alp="[A-Za-z]"
33 al_="[A-Za-z_]"
34 ALN="[A-Z0-9]"
35 AN_="[A-Z0-9_]"
36 aln="[A-Za-z0-9]"
37 an_="[A-Za-z0-9_]"
38 # to match something like 1ul, floats or hexes as well:
39 D="$int*\.\?$int\+x\?$hex*[uUlL]\{0,3\}[fF]\?"
40
41 # more strict and catches it (costs one backreference for (git-)grep)
42 d="\($int\+[uUlLfF]\?\|$int\+[uU]\?[lL][lL]\?\|0x$hex\+\|0x$HEX\+\|$i\+[lL][lL][uU]\|$i*\.$i\+[fF]\?\)"
43
44 # capital: can be used to catch a definition or config option
45 K="$UP_\+$AN_*";
46
47 # can be used for a variable/function name:
48 V="$an_\+$an_*"
49
50 # works the same as above, but also for members and arrays: one backreference
51 # is more strict
52 W="$V\(\[$s$V$s\]\|\[$s$D$s\]\|\.$V\|->$V\)*"
53 # catches it at once (less strict)
54 w="\($V\|${V}\[$s$an_*${s}\]\|$V\.\|$V->\)\+"
55
56 # seperators:
57 s="[[:space:]]*";
58 S="[[:space:]]\+"
59
60 # useful to delimit a variable name:
61 Q="[^[:alnum:]_]"
62
63 # match the end of the line, including comments: one backreference (but at eol)
64 cendl="$s\(\/[\*\/].*\)\?$"
65
66 # match something that is not comment, string or character: 2 backreferences
67 ccode="\([^\/\"']*\|\/[^\*\/]\|\/\*\([^\*]*\|\**[^\/\*]\)*\*\+\/\|'[^']*'\|\"[^\"]*\"\)*"
68
69 # resp function open and end (only works when indentation is correct.
70 fo="^[\{]$cendl"
71 fe="^[\}]$cendl"
72 se="^[\}];$cendl"
73
74 # to match nested parentheses
75 nps="[^()]*"
76 nstdps="\(($nps\(($nps\(($nps\(($nps\(($nps)$nps\)*)$nps\)*)$nps\)*)$nps\)*)$nps\)*"
77
78
79 # first determine unsigned typedefs
80 arr="\(\[[^\]]*\]$s\)*"
81 attr="__attribute__$s(([^;]*))"
82 utype="${s}typedef${S}unsigned$S\($V$S\)*"
83 uns="unsigned$(
84 git-grep "^$utype\($V$s$arr\|$attr$S$V$s$arr\|$V$s$arr$S$attr\)$s;$cendl" | sed -n "s/^[^.]*\.[hc]:$utype\(\($V\)$s$arr\|$attr$S\($V\)$s$arr\|\($V\)$s$arr$S$attr\)$s;$cendl/\\\\|\3\5\7/p" | sort | uniq | tr -d "\n")"
85
86 # define left and right operators
87 # to decrease the number backrefences, these are assigned in loops
88 opl=
89 for op in "[;,|^?:(]" "[\!+*/%&|~^-]=" ">>=" "<<=" "\[" "&&" "$an_$s&"; do
90 opl="$opl$op\|$op$s++\|$op$s--\|"
91 done
92 opl="\(${opl%|})"
93 opr=
94 for op in "[;,&|^?:)]" "[\!+*/%&|~^<>-]=" ">>=" "<<=" ">[^>]" "<[^<]" "\]"; do
95 opr="$opr$op\|$op$s++\|$op$s--\|"
96 done
97 opr="\(${opr%|})"
98
99 # string catches invalid comparison
100 q1="$opl$s\($w$s\(>=${s}0\|<${s}0\|[><\!=]=$s-$s$D\|[<>]$s-$s$D\)\|\(0$s>\|0$s<=\|-$s$D${s}[><\!=]=\|-$s$D${s}[<>]\)$s$w\)$s$opr"
101
102 start=0
103 end=$(echo $uns | tr -cd "|" | wc -c)
104
105 # main function
106 while [ $start -lt $end ]; do
107 # we match 30 typedefs at a time
108 tuns="$(echo $uns | cut -d "\\" -f$start-$(($start+29)))"
109
110 # catch candidate files
111 for f in $(git-grep -l "^\(${ccode}[,;]$s\)\?\($tuns\)$S" | grep "[^.]*\.[ch]" | xargs grep -l "$q1"); do
112 for n in $(sed -n "/^.*$q1/=" $f); do # lines
113 for v in $(sed -n "${n}s/^.*$q1.*$/\3\6/p" $f); do
114 # n2 = wine there
115 head -n$n $f | tac | sed -n "/^[{]/q; /^\(.*$Q\)\?\($tuns\)$S\($V$S\)*$v$Q.*$/=" | while read n2;
116 do
117 echo "# --- invalid test on unsigned variable '$v' --- #"
118 echo "vi $f +$n2 # unsigned declaration"
119 echo "vi $f +$n # invalid test"
120 done
121 done
122 done
123 done
124 start=$(($start+30))
125 done | less
126 --
127 To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in
128 the body of a message to majordomo@vger.kernel.org
129 More majordomo info at http://vger.kernel.org/majordomo-info.html