msg_247.c revision 1.30 1 /* $NetBSD: msg_247.c,v 1.30 2023/07/05 11:36:56 rillig Exp $ */
2 # 3 "msg_247.c"
3
4 // Test for message: pointer cast from '%s' to '%s' may be troublesome [247]
5
6 /*
7 * The word 'may' in the message text means that the trouble is not necessarily
8 * on this platform with its specific type sizes, but on other platforms.
9 *
10 * See also:
11 * msg_247_portable.c
12 * msg_247_lp64.c
13 */
14
15 /* lint1-extra-flags: -c -X 351 */
16
17 /* example taken from Xlib.h */
18 typedef struct {
19 int id;
20 } *PDisplay;
21
22 struct Other {
23 int id;
24 };
25
26 PDisplay
27 example(struct Other *arg)
28 {
29 /*
30 * Before tree.c 1.461 from 2022-06-24, lint warned about the cast
31 * between the structs.
32 *
33 * XXX: The target type was reported as 'struct <unnamed>'. In cases
34 * like these, it would be helpful to print at least the type name
35 * of the pointer. This type name though is discarded immediately
36 * in the grammar rule 'typespec: T_TYPENAME'.
37 * After that, the target type of the cast is just an unnamed struct,
38 * with no hint at all that there is a typedef for a pointer to the
39 * struct.
40 */
41 return (PDisplay)arg;
42 }
43
44 /*
45 * C code with a long history that has existed in pre-C90 times already often
46 * uses 'pointer to char' where modern code would use 'pointer to void'.
47 * Since 'char' is the most general underlying type, there is nothing wrong
48 * with casting to it. An example for this type of code is X11.
49 *
50 * Casting to 'pointer to char' may also be used by programmers who don't know
51 * about endianness, but that's not something lint can do anything about. The
52 * code for these two use cases looks exactly the same, so lint errs on the
53 * side of fewer false positive warnings here.
54 */
55 char *
56 cast_to_char_pointer(struct Other *arg)
57 {
58 return (char *)arg;
59 }
60
61 /*
62 * In traditional C there was 'unsigned char' as well, so the same reasoning
63 * as for plain 'char' applies here.
64 */
65 unsigned char *
66 cast_to_unsigned_char_pointer(struct Other *arg)
67 {
68 return (unsigned char *)arg;
69 }
70
71 /*
72 * Traditional C does not have the type specifier 'signed', which means that
73 * this type cannot be used by old code. Therefore warn about this. All code
74 * that triggers this warning should do the intermediate cast via 'void
75 * pointer'.
76 */
77 signed char *
78 cast_to_signed_char_pointer(struct Other *arg)
79 {
80 /* expect+1: warning: pointer cast from 'pointer to struct Other' to 'pointer to signed char' may be troublesome [247] */
81 return (signed char *)arg;
82 }
83
84 char *
85 cast_to_void_pointer_then_to_char_pointer(struct Other *arg)
86 {
87 return (char *)(void *)arg;
88 }
89
90
91 /*
92 * When implementing types that have a public part that is exposed to the user
93 * (in this case 'struct counter') and a private part that is only visible to
94 * the implementation (in this case 'struct counter_impl'), a common
95 * implementation technique is to use a struct in which the public part is the
96 * first member. C guarantees that the pointer to the first member is at the
97 * same address as the pointer to the whole struct.
98 *
99 * Seen in external/mpl/bind/dist/lib/isc/mem.c for 'struct isc_mem' and
100 * 'struct isc__mem'.
101 */
102
103 struct counter {
104 int count;
105 };
106
107 struct counter_impl {
108 struct counter public_part;
109 int saved_count;
110 };
111
112 void *allocate(void);
113
114 struct counter *
115 counter_new_typesafe(void)
116 {
117 struct counter_impl *impl = allocate();
118 impl->public_part.count = 12345;
119 impl->saved_count = 12346;
120 return &impl->public_part;
121 }
122
123 struct counter *
124 counter_new_cast(void)
125 {
126 struct counter_impl *impl = allocate();
127 impl->public_part.count = 12345;
128 impl->saved_count = 12346;
129 /* Before tree.c 1.462 from 2022-06-24, lint warned about this cast. */
130 return (struct counter *)impl;
131 }
132
133 void
134 counter_increment(struct counter *counter)
135 {
136 /*
137 * Before tree.c 1.272 from 2021-04-08, lint warned about the cast
138 * from 'struct counter' to 'struct counter_impl'.
139 */
140 struct counter_impl *impl = (struct counter_impl *)counter;
141 impl->saved_count = impl->public_part.count;
142 impl->public_part.count++;
143 }
144
145
146 /*
147 * In OpenSSL, the hashing API uses the incomplete 'struct lhash_st' for their
148 * type-generic hashing API while defining a separate struct for each type to
149 * be hashed.
150 *
151 * Before 2021-04-09, in a typical NetBSD build this led to about 38,000 lint
152 * warnings about possibly troublesome pointer casts.
153 */
154
155 /* expect+1: warning: struct 'lhash_st' never defined [233] */
156 struct lhash_st;
157
158 struct lhash_st *OPENSSL_LH_new(void);
159
160 struct lhash_st_OPENSSL_STRING {
161 union lh_OPENSSL_STRING_dummy {
162 void *d1;
163 unsigned long d2;
164 int d3;
165 } dummy;
166 };
167
168 # 196 "lhash.h" 1 3 4
169 struct lhash_st_OPENSSL_STRING *
170 lh_OPENSSL_STRING_new(void)
171 {
172 /*
173 * Since tree.c 1.274 from 2021-04-09, lint does not warn about casts
174 * to or from incomplete structs anymore.
175 */
176 return (struct lhash_st_OPENSSL_STRING *)OPENSSL_LH_new();
177 }
178 # 179 "msg_247.c" 2
179
180 void sink(const void *);
181
182 /*
183 * Before tree.c 1.316 from 2021-07-15, lint warned about pointer casts from
184 * unsigned char or plain char to another type. These casts often occur in
185 * traditional code that does not use void pointers, even 30 years after C90
186 * introduced 'void'.
187 */
188 void
189 unsigned_char_to_unsigned_type(unsigned char *ucp)
190 {
191 unsigned short *usp;
192
193 usp = (unsigned short *)ucp;
194 sink(usp);
195 }
196
197 /*
198 * Before tree.c 1.316 from 2021-07-15, lint warned about pointer casts from
199 * unsigned char or plain char to another type. These casts often occur in
200 * traditional code that does not use void pointers, even 30 years after C90
201 * introduced 'void'.
202 */
203 void
204 plain_char_to_unsigned_type(char *cp)
205 {
206 unsigned short *usp;
207
208 usp = (unsigned short *)cp;
209 sink(usp);
210 }
211
212 /*
213 * Before tree.c 1.460 from 2022-06-24, lint warned about pointer casts from
214 * unsigned char or plain char to a struct or union type. These casts often
215 * occur in traditional code that does not use void pointers, even 30 years
216 * after C90 introduced 'void'.
217 */
218 void
219 char_to_struct(void *ptr)
220 {
221
222 sink((struct counter *)(char *)ptr);
223
224 sink((struct counter *)(unsigned char *)ptr);
225
226 /* expect+1: warning: pointer cast from 'pointer to signed char' to 'pointer to struct counter' may be troublesome [247] */
227 sink((struct counter *)(signed char *)ptr);
228 }
229
230
231 // The following data types are simplified from various system headers.
232
233 typedef unsigned char uint8_t;
234 typedef unsigned short uint16_t;
235 typedef unsigned int uint32_t;
236
237 typedef uint16_t in_port_t;
238 typedef uint8_t sa_family_t;
239
240 struct sockaddr {
241 uint8_t sa_len;
242 sa_family_t sa_family;
243 char sa_data[14];
244 };
245
246 struct in_addr {
247 uint32_t s_addr;
248 };
249
250 struct sockaddr_in {
251 uint8_t sin_len;
252 sa_family_t sin_family;
253 in_port_t sin_port;
254 struct in_addr sin_addr;
255 uint8_t sin_zero[8];
256 };
257
258 struct sockaddr_in6 {
259 uint8_t sin6_len;
260 sa_family_t sin6_family;
261 in_port_t sin6_port;
262 uint32_t sin6_flowinfo;
263 union {
264 uint8_t u6_addr8[16];
265 uint16_t u6_addr16[8];
266 uint32_t u6_addr32[4];
267 } sin6_addr;
268 uint32_t sin6_scope_id;
269 };
270
271 /*
272 * Before tree.c 1.461 from 2022-06-24, lint warned about the cast between the
273 * sockaddr variants. Since then, lint allows casts between pointers to
274 * structs if the initial members have compatible types and either of the
275 * struct types continues with a byte array.
276 */
277 void *
278 cast_between_sockaddr_variants(void *ptr)
279 {
280
281 void *t1 = (struct sockaddr_in *)(struct sockaddr *)ptr;
282 void *t2 = (struct sockaddr *)(struct sockaddr_in *)t1;
283 void *t3 = (struct sockaddr_in6 *)(struct sockaddr *)t2;
284 void *t4 = (struct sockaddr *)(struct sockaddr_in6 *)t3;
285
286 /* expect+1: warning: pointer cast from 'pointer to struct sockaddr_in6' to 'pointer to struct sockaddr_in' may be troublesome [247] */
287 void *t5 = (struct sockaddr_in *)(struct sockaddr_in6 *)t4;
288
289 /* expect+1: warning: pointer cast from 'pointer to struct sockaddr_in' to 'pointer to struct sockaddr_in6' may be troublesome [247] */
290 void *t6 = (struct sockaddr_in6 *)(struct sockaddr_in *)t5;
291
292 return t6;
293 }
294
295
296 // From jemalloc.
297
298 typedef struct ctl_node_s {
299 _Bool named;
300 } ctl_node_t;
301
302 typedef struct ctl_named_node_s {
303 ctl_node_t node;
304 const char *name;
305 } ctl_named_node_t;
306
307 void *
308 cast_between_first_member_struct(void *ptr)
309 {
310 /* Before tree.c 1.462 from 2022-06-24, lint warned about this cast. */
311 void *t1 = (ctl_node_t *)(ctl_named_node_t *)ptr;
312
313 void *t2 = (ctl_named_node_t *)(ctl_node_t *)ptr;
314
315 return t2;
316 }
317
318 double *
319 unnecessary_cast_from_array_to_pointer(int dim)
320 {
321 static double storage_1d[10];
322 static double storage_2d[10][5];
323
324 if (dim == 1)
325 return (double *)storage_1d;
326
327 if (dim == -1)
328 return storage_1d;
329
330 if (dim == 2)
331 /* expect+1: warning: illegal combination of 'pointer to double' and 'pointer to array[5] of double' [184] */
332 return storage_2d;
333
334 /*
335 * C11 6.3.2.1p3 says that an array is converted to a pointer to its
336 * first element. That paragraph doesn't say 'recursively', that
337 * word is only used two paragraphs above, in 6.3.2.1p1.
338 */
339 if (dim == -2)
340 return storage_2d[0];
341
342 return (double *)storage_2d;
343 }
344
345
346 typedef void (*function)(void);
347
348 typedef struct {
349 function m_function_array[5];
350 } struct_function_array;
351
352 typedef union {
353 int um_int;
354 double um_double;
355 struct_function_array um_function_array;
356 } anything;
357
358 static int *p_int;
359 static double *p_double;
360 static function p_function;
361 static struct_function_array *p_function_array;
362 static anything *p_anything;
363
364 void
365 conversions_from_and_to_union(void)
366 {
367 /* Self-assignment, disguised by a cast to its own type. */
368 p_int = (int *)p_int;
369 /* Self-assignment, disguised by a cast to a pointer. */
370 p_int = (void *)p_int;
371
372 /* expect+1: warning: illegal combination of 'pointer to int' and 'pointer to double', op '=' [124] */
373 p_int = p_double;
374 /* expect+1: warning: pointer cast from 'pointer to double' to 'pointer to int' may be troublesome [247] */
375 p_int = (int *)p_double;
376
377 /* expect+1: warning: illegal combination of 'pointer to union typedef anything' and 'pointer to double', op '=' [124] */
378 p_anything = p_double;
379 /* OK, since the union 'anything' has a 'double' member. */
380 p_anything = (anything *)p_double;
381 /* expect+1: warning: illegal combination of 'pointer to double' and 'pointer to union typedef anything', op '=' [124] */
382 p_double = p_anything;
383 /* OK, since the union 'anything' has a 'double' member. */
384 p_double = (double *)p_anything;
385
386 /*
387 * Casting to an intermediate union does not make casting between two
388 * incompatible types better.
389 */
390 /* expect+1: warning: illegal combination of 'pointer to function(void) returning void' and 'pointer to union typedef anything', op '=' [124] */
391 p_function = (anything *)p_int;
392
393 /* expect+2: warning: converting 'pointer to function(void) returning void' to 'pointer to union typedef anything' is questionable [229] */
394 /* expect+1: warning: illegal combination of 'pointer to function(void) returning void' and 'pointer to union typedef anything', op '=' [124] */
395 p_function = (anything *)p_function_array->m_function_array[0];
396
397 /* expect+1: warning: illegal combination of 'pointer to int' and 'pointer to function(void) returning void', op '=' [124] */
398 p_int = p_function;
399 }
400