Home | History | Annotate | Line # | Download | only in lint1
      1 /*	$NetBSD: msg_135.c,v 1.17 2025/03/21 20:37:31 rillig Exp $	*/
      2 # 3 "msg_135.c"
      3 
      4 // Test for message: converting '%s' to '%s' increases alignment from %u to %u [135]
      5 
      6 /* lint1-extra-flags: -h -X 351 */
      7 
      8 void sink(const void *);
      9 
     10 unsigned
     11 read_uint(const unsigned short **pp)
     12 {
     13 	unsigned val;
     14 
     15 	/* expect+1: warning: converting 'pointer to const unsigned short' to 'pointer to const unsigned int' increases alignment from 2 to 4 [135] */
     16 	val = *(const unsigned *)(*pp);
     17 	pp += sizeof(unsigned);
     18 	return val;
     19 }
     20 
     21 /* expect+1: warning: struct 'incomplete' never defined [233] */
     22 struct incomplete;
     23 
     24 struct complete {
     25 	int member;
     26 };
     27 
     28 /*
     29  * These types of conversions are typically seen in OpenSSL, when converting
     30  * from the publicly visible, incomplete 'struct lhash_st' to a private
     31  * implementation type such as 'struct lhash_st_OPENSSL_STRING'.
     32  *
     33  * Before tree.c 1.277 from 2021-04-17, lint warned about this, even though
     34  * there was not enough evidence that there really was an alignment problem,
     35  * resulting in many false positives.
     36  *
     37  * See openssl/lhash.h.
     38  */
     39 void
     40 pointer_to_structs(struct incomplete *incomplete)
     41 {
     42 	struct complete *complete;
     43 
     44 	complete = (struct complete *)incomplete;
     45 	sink(complete);
     46 }
     47 
     48 /*
     49  * Before tree.c 1.316 from 2021-07-15, lint warned about pointer casts from
     50  * unsigned char or plain char to another type.  These casts often occur in
     51  * traditional code that does not use void pointers, even 30 years after C90
     52  * introduced 'void'.
     53  */
     54 void
     55 unsigned_char_to_unsigned_type(unsigned char *ucp)
     56 {
     57 	unsigned short *usp;
     58 
     59 	usp = (unsigned short *)ucp;
     60 	sink(usp);
     61 }
     62 
     63 /*
     64  * Before tree.c 1.316 from 2021-07-15, lint warned about pointer casts from
     65  * unsigned char or plain char to another type.  These casts often occur in
     66  * traditional code that does not use void pointers, even 30 years after C90
     67  * introduced 'void'.
     68  */
     69 void
     70 plain_char_to_unsigned_type(char *cp)
     71 {
     72 	unsigned short *usp;
     73 
     74 	usp = (unsigned short *)cp;
     75 	sink(usp);
     76 }
     77 
     78 /*
     79  * Converting a pointer with a low alignment requirement to a union that
     80  * includes other types with higher alignment requirements is considered safe.
     81  * While accessing any other member of the union might trigger an alignment
     82  * violation, such an access is not likely from an application point of view,
     83  * as it would access undefined memory and thus invoke undefined behavior.
     84  *
     85  * A practical case for this pattern are tagged unions, in which the first
     86  * member of the struct determines how the remaining members are interpreted.
     87  * See sbin/newfs_udf, function udf_validate_tag_and_crc_sums for an example.
     88  *
     89  * C99 6.2.5p26 defines the representation and alignment of types, stating
     90  * that pointers to union types need not have the same representation and
     91  * alignment as pointers to other types.
     92  *
     93  * C99 6.7.2.1p14 and C23 6.7.2.1p18 both state that a "pointer to a union
     94  * object [...] points to each of its members [...], and vice versa".
     95  */
     96 double
     97 cast_to_union(void)
     98 {
     99 	int align_4 = 0;
    100 	double align_8 = 0.0;
    101 	union both {
    102 		int p_align_4;
    103 		double p_align_8;
    104 	} *both;
    105 
    106 	both = (union both *)&align_4;
    107 	both = (union both *)&align_8;
    108 	return both->p_align_8;
    109 }
    110 
    111 /*
    112  * Structures with alignment 1 typically contain padding arrays only, so don't
    113  * warn when they are converted to their structured counterparts.  An example
    114  * of such a conversion is from 'struct sockaddr' to 'struct sockaddr_in6'.
    115  */
    116 void
    117 from_alignment_1_to_8(void)
    118 {
    119 	struct alignment_1 {
    120 		char filler[32];
    121 	};
    122 	struct alignment_8 {
    123 		char filler[32];
    124 		double numbers[4];
    125 	};
    126 
    127 	static struct alignment_1 *pointer_1;
    128 	static struct alignment_8 *pointer_8;
    129 
    130 	pointer_8 = (struct alignment_8 *)pointer_1;
    131 	pointer_1 = (struct alignment_1 *)pointer_8;
    132 }
    133