msg_117.c revision 1.16 1 /* $NetBSD: msg_117.c,v 1.16 2025/09/14 14:42:52 rillig Exp $ */
2 # 3 "msg_117.c"
3
4 // Test for message: bitwise '%s' on signed '%s' possibly nonportable [117]
5
6 /* lint1-extra-flags: -p -X 351 */
7
8 signed char s8;
9 unsigned char u8;
10 short s16;
11 unsigned short u16;
12 int s32;
13 unsigned u32;
14 long long s64;
15 unsigned long long u64;
16
17 // Shifting a signed integer left invokes undefined behavior if a 1 is shifted
18 // to the sign bit or beyond. At runtime, KUBSAN performs this check.
19 void
20 shl(void)
21 {
22 s32 = s8 << 0;
23 s32 = s8 << 23;
24 /* expect+1: warning: bitwise '<<' on signed 'int promoted from signed char' possibly nonportable [117] */
25 s32 = s8 << 24;
26 s32 = s8 << 31;
27 /* expect+1: warning: shift amount 32 equals bit-size of 'int promoted from signed char' [267] */
28 s32 = s8 << 32;
29 /* expect+1: warning: shift amount 32 equals bit-size of 'int promoted from signed char' [267] */
30 s64 = s8 << 32;
31
32 /*
33 * When shifting 'uint8_t', it first gets promoted to 'int', which is
34 * then subject to the overflow check. To prevent this, first cast the
35 * 'uint8_t' to a suitable larger unsigned integer type.
36 */
37 u32 = u8 << 0;
38 u32 = u8 << 23;
39 /* expect+1: warning: bitwise '<<' on signed 'int promoted from unsigned char' possibly nonportable [117] */
40 u32 = u8 << 24;
41 u32 = u8 << 31;
42 /* expect+1: warning: shift amount 32 equals bit-size of 'int promoted from unsigned char' [267] */
43 u32 = u8 << 32;
44 /* expect+1: warning: shift amount 32 equals bit-size of 'int promoted from unsigned char' [267] */
45 u64 = u8 << 32;
46
47 u32 = s32 << 0;
48 u32 = s32 << 23;
49 u32 = s32 << 24;
50 u32 = s32 << 31;
51 /* expect+1: warning: shift amount 32 equals bit-size of 'int' [267] */
52 u32 = s32 << 32;
53 /* expect+1: warning: shift amount 32 equals bit-size of 'int' [267] */
54 u64 = s32 << 32;
55
56 u32 = u32 << 0;
57 u32 = u32 << 23;
58 u32 = u32 << 24;
59 u32 = u32 << 31;
60 /* expect+1: warning: shift amount 32 equals bit-size of 'unsigned int' [267] */
61 u32 = u32 << 32;
62 /* expect+1: warning: shift amount 32 equals bit-size of 'unsigned int' [267] */
63 u64 = u32 << 32;
64 }
65
66 int
67 shr(int a, int b)
68 {
69 /* expect+1: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
70 return a >> b;
71 }
72
73 int
74 shr_lhs_constant_positive(int a)
75 {
76 return 0x1234 >> a;
77 }
78
79 int
80 shr_lhs_constant_negative(int a)
81 {
82 /* expect+1: warning: bitwise '>>' on signed 'int' nonportable [120] */
83 return -0x1234 >> a;
84 }
85
86 int
87 shr_rhs_constant_positive(int a)
88 {
89 /* expect+2: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
90 /* expect+1: warning: shift amount 4660 is greater than bit-size 32 of 'int' [122] */
91 return a >> 0x1234;
92 }
93
94 int
95 shr_rhs_constant_negative(int a)
96 {
97 /* expect+2: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
98 /* expect+1: warning: negative shift [121] */
99 return a >> -0x1234;
100 }
101
102 unsigned int
103 shr_unsigned_char(unsigned char uc)
104 {
105 /*
106 * Even though 'uc' is promoted to 'int', it cannot be negative.
107 * Before tree.c 1.335 from 2021-08-15, lint wrongly warned that
108 * 'uc >> 4' might be a bitwise '>>' on signed value.
109 */
110 return uc >> 4;
111 }
112
113 unsigned char
114 shr_unsigned_char_promoted_signed(unsigned char bit)
115 {
116 /*
117 * The possible values for 'bit' range from 0 to 255. Subtracting 1
118 * from 0 results in a negative expression value.
119 */
120 /* expect+1: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
121 return (unsigned char)((bit - 1) >> 5);
122 }
123
124 unsigned char
125 shr_unsigned_char_promoted_unsigned(unsigned char bit)
126 {
127 /*
128 * To prevent the above warning, the intermediate expression must be
129 * cast to 'unsigned char'.
130 */
131 return (unsigned char)((unsigned char)(bit - 1) >> 5);
132 }
133
134 /*
135 * C90 3.3.7, C99 6.5.7 and C11 6.5.7 all say the same: If E1 has a signed
136 * type and a negative value, the resulting value is implementation-defined.
137 *
138 * These standards don't guarantee anything about the lower bits of the
139 * resulting value, which are generally independent of whether the shift is
140 * performed in signed arithmetics or in unsigned arithmetics. The C99
141 * rationale talks about signed shifts, but does not provide any guarantee
142 * either. It merely suggests that platforms are free to use unsigned shifts
143 * even if the operand type is signed.
144 *
145 * K&R provides more guarantees by saying: Right shifting a signed quantity
146 * will fill with sign bits ("arithmetic shift") on some machines such as the
147 * PDP-11, and with 0-bits ("logical shift") on others.
148 *
149 * https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html says:
150 * Signed '>>' acts on negative numbers by sign extension.
151 *
152 * This means that at least in GCC mode, lint may decide to not warn about
153 * these cases.
154 */
155 void
156 shr_signed_ignoring_high_bits(int x)
157 {
158
159 /*
160 * All sane platforms should define that 'x >> 0 == x', even if x is
161 * negative.
162 */
163 /* expect+1: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
164 if (x >> 0 != 0)
165 return;
166
167 /*
168 * If x is negative, x >> 1 is nonzero, no matter whether the shift
169 * is arithmetic or logical.
170 */
171 /* expect+1: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
172 if (x >> 1 != 0)
173 return;
174
175 /*
176 * The highest bit may be 0 or 1, the others should be well-defined
177 * on all sane platforms, making it irrelevant whether the actual
178 * shift operation is arithmetic or logical.
179 */
180 /* expect+1: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
181 if (((x >> 1) & 1) != 0)
182 return;
183
184 /*
185 * The result of this expression is the same with arithmetic and
186 * logical shifts since the filled bits are masked out.
187 */
188 /* expect+1: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
189 if (((x >> 31) & 1) != 0)
190 return;
191
192 /*
193 * In this case, arithmetic shift results in 2 while logical shift
194 * results in 0. This difference is what this warning is about.
195 */
196 /* expect+1: warning: bitwise '>>' on signed 'int' possibly nonportable [117] */
197 if (((x >> 31) & 2) != 0)
198 return;
199
200 /*
201 * The result of '&' is guaranteed to be positive, so don't warn.
202 * Code like this typically occurs in hexdump functions.
203 */
204 if ((x & 0xf0) >> 4 != 0)
205 return;
206 }
207