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
14virtual context
15virtual org
16virtual report
17
18@initialize:python@
19@@
20
21def 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
51def 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
61def 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@
66expression f;
67long l: script:python() { filter_out_safe_constants(l) };
68unsigned long ul : script:python() { filter_out_safe_constants(ul) };
69u64 ul64 : script:python() { filter_out_safe_constants(ul64) };
70s64 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)@
84expression f;
85position p;
86long l: script:python() { filter_out_safe_constants(l) };
87unsigned long ul : script:python() { filter_out_safe_constants(ul) };
88u64 ul64 : script:python() { filter_out_safe_constants(ul64) };
89s64 sl64 : script:python() { filter_out_safe_constants(sl64) };
90@@
91(
92do_div@p(f, l);
93|
94do_div@p(f, ul);
95|
96do_div@p(f, ul64);
97|
98do_div@p(f, sl64);
99)
100
101@script:python depends on org@
102p << r.p;
103ul << r.ul;
104@@
105
106coccilib.org.print_todo(p[0], construct_warnings("div64_ul"))
107
108@script:python depends on org@
109p << r.p;
110l << r.l;
111@@
112
113coccilib.org.print_todo(p[0], construct_warnings("div64_long"))
114
115@script:python depends on org@
116p << r.p;
117ul64 << r.ul64;
118@@
119
120coccilib.org.print_todo(p[0], construct_warnings("div64_u64"))
121
122@script:python depends on org@
123p << r.p;
124sl64 << r.sl64;
125@@
126
127coccilib.org.print_todo(p[0], construct_warnings("div64_s64"))
128
129@script:python depends on report@
130p << r.p;
131ul << r.ul;
132@@
133
134coccilib.report.print_report(p[0], construct_warnings("div64_ul"))
135
136@script:python depends on report@
137p << r.p;
138l << r.l;
139@@
140
141coccilib.report.print_report(p[0], construct_warnings("div64_long"))
142
143@script:python depends on report@
144p << r.p;
145sl64 << r.sl64;
146@@
147
148coccilib.report.print_report(p[0], construct_warnings("div64_s64"))
149
150@script:python depends on report@
151p << r.p;
152ul64 << r.ul64;
153@@
154
155coccilib.report.print_report(p[0], construct_warnings("div64_u64"))
156