1 /* $NetBSD: msg_247.c,v 1.13 2021/04/09 20:00:07 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 * when the parser reduces 'T_TYPENAME clrtyp' to 'clrtyp_typespec'. 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 struct lhash_st; /* expect: struct lhash_st never defined */ 135 136 struct lhash_st *OPENSSL_LH_new(void); 137 138 struct lhash_st_OPENSSL_STRING { 139 union lh_OPENSSL_STRING_dummy { 140 void *d1; 141 unsigned long d2; 142 int d3; 143 } dummy; 144 }; 145 146 # 196 "lhash.h" 1 3 4 147 struct lhash_st_OPENSSL_STRING * 148 lh_OPENSSL_STRING_new(void) 149 { 150 /* 151 * Since tree.c 1.274 from 2021-04-09, lint does not warn about casts 152 * to or from incomplete structs anymore. 153 */ 154 return (struct lhash_st_OPENSSL_STRING *)OPENSSL_LH_new(); 155 } 156 # 157 "msg_247.c" 2 157