Skip to content

Commit ac5f313

Browse files
tasksetJuliaLawall
authored andcommitted
coccinelle: semantic patch to check for inappropriate do_div() calls
do_div() does a 64-by-32 division. When the divisor is unsigned long, u64, or s64, do_div() truncates it to 32 bits, this means it can test non-zero and be truncated to zero for division. This semantic patch is inspired by Mateusz Guzik's patch: commit b0ab99e ("sched: Fix possible divide by zero in avg_atom() calculation") Signed-off-by: Wen Yang <[email protected]> Signed-off-by: Julia Lawall <[email protected]> Cc: Gilles Muller <[email protected]> Cc: Nicolas Palix <[email protected]> Cc: Michal Marek <[email protected]> Cc: Matthias Maennich <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Masahiro Yamada <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: [email protected]
1 parent c605c39 commit ac5f313

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

scripts/coccinelle/misc/do_div.cocci

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/// do_div() does a 64-by-32 division.
3+
/// When the divisor is long, unsigned long, u64, or s64,
4+
/// do_div() truncates it to 32 bits, this means it can test
5+
/// non-zero and be truncated to 0 for division on 64bit platforms.
6+
///
7+
//# This makes an effort to find those inappropriate do_div() calls.
8+
//
9+
// Confidence: Moderate
10+
// Copyright: (C) 2020 Wen Yang, Alibaba.
11+
// Comments:
12+
// Options: --no-includes --include-headers
13+
14+
virtual context
15+
virtual org
16+
virtual report
17+
18+
@initialize:python@
19+
@@
20+
21+
def get_digit_type_and_value(str):
22+
is_digit = False
23+
value = 0
24+
25+
try:
26+
if (str.isdigit()):
27+
is_digit = True
28+
value = int(str, 0)
29+
elif (str.upper().endswith('ULL')):
30+
is_digit = True
31+
value = int(str[:-3], 0)
32+
elif (str.upper().endswith('LL')):
33+
is_digit = True
34+
value = int(str[:-2], 0)
35+
elif (str.upper().endswith('UL')):
36+
is_digit = True
37+
value = int(str[:-2], 0)
38+
elif (str.upper().endswith('L')):
39+
is_digit = True
40+
value = int(str[:-1], 0)
41+
elif (str.upper().endswith('U')):
42+
is_digit = True
43+
value = int(str[:-1], 0)
44+
except Exception as e:
45+
print('Error:',e)
46+
is_digit = False
47+
value = 0
48+
finally:
49+
return is_digit, value
50+
51+
def filter_out_safe_constants(str):
52+
is_digit, value = get_digit_type_and_value(str)
53+
if (is_digit):
54+
if (value >= 0x100000000):
55+
return True
56+
else:
57+
return False
58+
else:
59+
return True
60+
61+
def construct_warnings(suggested_fun):
62+
msg="WARNING: do_div() does a 64-by-32 division, please consider using %s instead."
63+
return msg % suggested_fun
64+
65+
@depends on context@
66+
expression f;
67+
long l: script:python() { filter_out_safe_constants(l) };
68+
unsigned long ul : script:python() { filter_out_safe_constants(ul) };
69+
u64 ul64 : script:python() { filter_out_safe_constants(ul64) };
70+
s64 sl64 : script:python() { filter_out_safe_constants(sl64) };
71+
72+
@@
73+
(
74+
* do_div(f, l);
75+
|
76+
* do_div(f, ul);
77+
|
78+
* do_div(f, ul64);
79+
|
80+
* do_div(f, sl64);
81+
)
82+
83+
@r depends on (org || report)@
84+
expression f;
85+
position p;
86+
long l: script:python() { filter_out_safe_constants(l) };
87+
unsigned long ul : script:python() { filter_out_safe_constants(ul) };
88+
u64 ul64 : script:python() { filter_out_safe_constants(ul64) };
89+
s64 sl64 : script:python() { filter_out_safe_constants(sl64) };
90+
@@
91+
(
92+
do_div@p(f, l);
93+
|
94+
do_div@p(f, ul);
95+
|
96+
do_div@p(f, ul64);
97+
|
98+
do_div@p(f, sl64);
99+
)
100+
101+
@script:python depends on org@
102+
p << r.p;
103+
ul << r.ul;
104+
@@
105+
106+
coccilib.org.print_todo(p[0], construct_warnings("div64_ul"))
107+
108+
@script:python depends on org@
109+
p << r.p;
110+
l << r.l;
111+
@@
112+
113+
coccilib.org.print_todo(p[0], construct_warnings("div64_long"))
114+
115+
@script:python depends on org@
116+
p << r.p;
117+
ul64 << r.ul64;
118+
@@
119+
120+
coccilib.org.print_todo(p[0], construct_warnings("div64_u64"))
121+
122+
@script:python depends on org@
123+
p << r.p;
124+
sl64 << r.sl64;
125+
@@
126+
127+
coccilib.org.print_todo(p[0], construct_warnings("div64_s64"))
128+
129+
@script:python depends on report@
130+
p << r.p;
131+
ul << r.ul;
132+
@@
133+
134+
coccilib.report.print_report(p[0], construct_warnings("div64_ul"))
135+
136+
@script:python depends on report@
137+
p << r.p;
138+
l << r.l;
139+
@@
140+
141+
coccilib.report.print_report(p[0], construct_warnings("div64_long"))
142+
143+
@script:python depends on report@
144+
p << r.p;
145+
sl64 << r.sl64;
146+
@@
147+
148+
coccilib.report.print_report(p[0], construct_warnings("div64_s64"))
149+
150+
@script:python depends on report@
151+
p << r.p;
152+
ul64 << r.ul64;
153+
@@
154+
155+
coccilib.report.print_report(p[0], construct_warnings("div64_u64"))

0 commit comments

Comments
 (0)