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