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