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