Home | History | Annotate | Line # | Download | only in lint1
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