Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 b0ab99e7736a ("sched: Fix possible divide by zero in avg_atom() calculation")

Signed-off-by: Wen Yang <wenyang@linux.alibaba.com>
Signed-off-by: Julia Lawall <julia.lawall@inria.fr>
Cc: Gilles Muller <Gilles.Muller@lip6.fr>
Cc: Nicolas Palix <nicolas.palix@imag.fr>
Cc: Michal Marek <michal.lkml@markovi.net>
Cc: Matthias Maennich <maennich@google.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: cocci@systeme.lip6.fr
Cc: linux-kernel@vger.kernel.org

authored by

Wen Yang and committed by
Julia Lawall
ac5f3136 c605c396

+155
+155
scripts/coccinelle/misc/do_div.cocci
··· 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"))