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