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