msg_247.c revision 1.17 1 /* $NetBSD: msg_247.c,v 1.17 2022/06/11 11:52:13 rillig Exp $ */
2 # 3 "msg_247.c"
3
4 // Test for message: pointer cast from '%s' to '%s' may be troublesome [247]
5
6 /* lint1-extra-flags: -c */
7
8 /* example taken from Xlib.h */
9 typedef struct {
10 int id;
11 } *PDisplay;
12
13 struct Other {
14 int id;
15 };
16
17 void
18 example(struct Other *arg)
19 {
20 PDisplay display;
21
22 /*
23 * XXX: The target type is reported as 'struct <unnamed>'. In cases
24 * like these, it would be helpful to print at least the type name
25 * of the pointer. This type name though is discarded immediately
26 * in the grammar rule 'typespec: T_TYPENAME'.
27 * After that, the target type of the cast is just an unnamed struct,
28 * with no hint at all that there is a typedef for a pointer to the
29 * struct.
30 */
31 display = (PDisplay)arg; /* expect: 247 */
32 }
33
34 /*
35 * C code with a long history that has existed in pre-C90 times already often
36 * uses 'pointer to char' where modern code would use 'pointer to void'.
37 * Since 'char' is the most general underlying type, there is nothing wrong
38 * with casting to it. An example for this type of code is X11.
39 *
40 * Casting to 'pointer to char' may also be used by programmers who don't know
41 * about endianness, but that's not something lint can do anything about. The
42 * code for these two use cases looks exactly the same, so lint errs on the
43 * side of fewer false positive warnings here.
44 */
45 char *
46 cast_to_char_pointer(struct Other *arg)
47 {
48 return (char *)arg;
49 }
50
51 /*
52 * In traditional C there was 'unsigned char' as well, so the same reasoning
53 * as for plain 'char' applies here.
54 */
55 unsigned char *
56 cast_to_unsigned_char_pointer(struct Other *arg)
57 {
58 return (unsigned char *)arg;
59 }
60
61 /*
62 * Traditional C does not have the type specifier 'signed', which means that
63 * this type cannot be used by old code. Therefore warn about this. All code
64 * that triggers this warning should do the intermediate cast via 'void
65 * pointer'.
66 */
67 signed char *
68 cast_to_signed_char_pointer(struct Other *arg)
69 {
70 return (signed char *)arg; /* expect: 247 */
71 }
72
73 char *
74 cast_to_void_pointer_then_to_char_pointer(struct Other *arg)
75 {
76 return (char *)(void *)arg;
77 }
78
79
80 /*
81 * When implementing types that have a public part that is exposed to the user
82 * (in this case 'struct counter') and a private part that is only visible to
83 * the implementation (in this case 'struct counter_impl'), a common
84 * implementation technique is to use a struct in which the public part is the
85 * first member. C guarantees that the pointer to the first member is at the
86 * same address as the pointer to the whole struct.
87 *
88 * Seen in external/mpl/bind/dist/lib/isc/mem.c for 'struct isc_mem' and
89 * 'struct isc__mem'.
90 */
91
92 struct counter {
93 int count;
94 };
95
96 struct counter_impl {
97 struct counter public_part;
98 int saved_count;
99 };
100
101 void *allocate(void);
102
103 struct counter *
104 counter_new(void)
105 {
106 struct counter_impl *impl = allocate();
107 impl->public_part.count = 12345;
108 impl->saved_count = 12346;
109 return &impl->public_part;
110 }
111
112 void
113 counter_increment(struct counter *counter)
114 {
115 /*
116 * Before tree.c 1.272 from 2021-04-08, lint warned about the cast
117 * from 'struct counter' to 'struct counter_impl'.
118 */
119 struct counter_impl *impl = (struct counter_impl *)counter;
120 impl->saved_count = impl->public_part.count;
121 impl->public_part.count++;
122 }
123
124
125 /*
126 * In OpenSSL, the hashing API uses the incomplete 'struct lhash_st' for their
127 * type-generic hashing API while defining a separate struct for each type to
128 * be hashed.
129 *
130 * Before 2021-04-09, in a typical NetBSD build this led to about 38,000 lint
131 * warnings about possibly troublesome pointer casts.
132 */
133
134 /* expect+1: warning: struct 'lhash_st' never defined [233] */
135 struct lhash_st;
136
137 struct lhash_st *OPENSSL_LH_new(void);
138
139 struct lhash_st_OPENSSL_STRING {
140 union lh_OPENSSL_STRING_dummy {
141 void *d1;
142 unsigned long d2;
143 int d3;
144 } dummy;
145 };
146
147 # 196 "lhash.h" 1 3 4
148 struct lhash_st_OPENSSL_STRING *
149 lh_OPENSSL_STRING_new(void)
150 {
151 /*
152 * Since tree.c 1.274 from 2021-04-09, lint does not warn about casts
153 * to or from incomplete structs anymore.
154 */
155 return (struct lhash_st_OPENSSL_STRING *)OPENSSL_LH_new();
156 }
157 # 158 "msg_247.c" 2
158
159 void sink(const void *);
160
161 /*
162 * Before tree.c 1.316 from 2021-07-15, lint warned about pointer casts from
163 * unsigned char or plain char to another type. These casts often occur in
164 * traditional code that does not use void pointers, even 30 years after C90
165 * introduced 'void'.
166 */
167 void
168 unsigned_char_to_unsigned_type(unsigned char *ucp)
169 {
170 unsigned short *usp;
171
172 usp = (unsigned short *)ucp;
173 sink(usp);
174 }
175
176 /*
177 * Before tree.c 1.316 from 2021-07-15, lint warned about pointer casts from
178 * unsigned char or plain char to another type. These casts often occur in
179 * traditional code that does not use void pointers, even 30 years after C90
180 * introduced 'void'.
181 */
182 void
183 plain_char_to_unsigned_type(char *cp)
184 {
185 unsigned short *usp;
186
187 usp = (unsigned short *)cp;
188 sink(usp);
189 }
190