msg_168.c revision 1.13
1/*	$NetBSD: msg_168.c,v 1.13 2024/03/30 17:12:26 rillig Exp $	*/
2# 3 "msg_168.c"
3
4// Test for message: array subscript %ju cannot be > %d [168]
5
6/* lint1-extra-flags: -X 351 */
7
8void print_string(const char *);
9void print_char(char);
10
11void
12example(void)
13{
14	char buf[20] = {};	/* empty initializer is a GCC extension */
15
16	print_string(buf + 19);	/* inside the array */
17
18	/*
19	 * It is valid to point at the end of the array, but reading a
20	 * character from there invokes undefined behavior.
21	 *
22	 * The pointer to the end of the array is typically used in (begin,
23	 * end) tuples.  These are more common in C++ than in C though.
24	 */
25	print_string(buf + 20);
26
27	print_string(buf + 21);	/* undefined behavior, not detected */
28
29	print_char(buf[19]);
30	/* expect+1: warning: array subscript 20 cannot be > 19 [168] */
31	print_char(buf[20]);
32}
33
34void
35array_with_c99_initializer(void)
36{
37	static const char *const to_roman[] = {
38	    ['0'] = "undefined",
39	    ['5'] = "V",
40	    ['9'] = "IX"
41	};
42
43	print_string(to_roman['9']);
44	/* expect+1: warning: array subscript 58 cannot be > 57 [168] */
45	print_string(to_roman[':']);
46}
47
48
49/*
50 * In its expression tree, lint represents pointer addition as 'ptr + off',
51 * where 'off' is the offset in bytes, regardless of the pointer type.
52 *
53 * In the below code, the member 'offset_8' has type 'short', and the
54 * expression 's->offset_8' is represented as '&s + 8', or more verbose:
55 *
56 *	'+' type 'pointer to short'
57 *		'&' type 'pointer to struct s'
58 *			'name' 's' with auto 'array[1] of struct s', lvalue
59 *		'constant' type 'long', value 8
60 *
61 * The constant 8 differs from the usual model of pointer arithmetics.  Since
62 * the type of the '&' expression is 'pointer to struct s', adding a constant
63 * would rather be interpreted as adding 'constant * sizeof(struct s)', and
64 * to access a member, the pointer to 'struct s' would need to be converted
65 * to 'pointer of byte' first, then adding the offset 8, then converting the
66 * pointer to the target type 'pointer to short'.
67 *
68 * Lint uses the simpler representation, saving a few conversions on the way.
69 * Without this pre-multiplied representation, the below code would generate
70 * warnings about out-of-bounds array access, starting with offset_1.
71 */
72struct s {
73	char offset_0;
74	char offset_1;
75	int offset_4;
76	short offset_8;
77	char offset_10;
78};
79
80struct s
81s_init(void)
82{
83	struct s s[1];
84	s->offset_0 = 1;
85	s->offset_1 = 2;
86	s->offset_4 = 3;
87	s->offset_8 = 4;
88	s->offset_10 = 5;
89	return s[0];
90}
91