msg_168.c revision 1.9
11.9Srillig/*	$NetBSD: msg_168.c,v 1.9 2022/06/16 16:58:36 rillig Exp $	*/
21.1Srillig# 3 "msg_168.c"
31.1Srillig
41.1Srillig// Test for message: array subscript cannot be > %d: %ld [168]
51.1Srillig
61.2Srilligvoid print_string(const char *);
71.2Srilligvoid print_char(char);
81.2Srillig
91.2Srilligvoid
101.2Srilligexample(void)
111.2Srillig{
121.4Srillig	char buf[20] = {};	/* empty initializer is a GCC extension */
131.2Srillig
141.2Srillig	print_string(buf + 19);	/* inside the array */
151.2Srillig
161.2Srillig	/*
171.2Srillig	 * It is valid to point at the end of the array, but reading a
181.2Srillig	 * character from there invokes undefined behavior.
191.2Srillig	 *
201.2Srillig	 * The pointer to the end of the array is typically used in (begin,
211.2Srillig	 * end) tuples.  These are more common in C++ than in C though.
221.2Srillig	 */
231.2Srillig	print_string(buf + 20);
241.2Srillig
251.2Srillig	print_string(buf + 21);	/* undefined behavior, not detected */
261.2Srillig
271.2Srillig	print_char(buf[19]);
281.9Srillig	/* expect+1: warning: array subscript cannot be > 19: 20 [168] */
291.9Srillig	print_char(buf[20]);
301.2Srillig}
311.3Srillig
321.3Srilligvoid
331.3Srilligarray_with_c99_initializer(void)
341.3Srillig{
351.3Srillig	static const char *const to_roman[] = {
361.3Srillig	    ['0'] = "undefined",
371.3Srillig	    ['5'] = "V",
381.3Srillig	    ['9'] = "IX"
391.3Srillig	};
401.3Srillig
411.5Srillig	print_string(to_roman['9']);
421.9Srillig	/* expect+1: warning: array subscript cannot be > 57: 58 [168] */
431.9Srillig	print_string(to_roman[':']);
441.3Srillig}
451.6Srillig
461.6Srillig
471.8Srillig/*
481.8Srillig * In its expression tree, lint represents pointer addition as 'ptr + off',
491.8Srillig * where 'off' is the offset in bytes, regardless of the pointer type.
501.8Srillig *
511.8Srillig * In the below code, the member 'offset_8' has type 'short', and the
521.8Srillig * expression 's->offset_8' is represented as '&s + 8', or more verbose:
531.8Srillig *
541.8Srillig *	'+' type 'pointer to short'
551.8Srillig *		'&' type 'pointer to struct s'
561.8Srillig *			'name' 's' with auto 'array[1] of struct s', lvalue
571.8Srillig *		'constant' type 'long', value 8
581.8Srillig *
591.8Srillig * The constant 8 differs from the usual model of pointer arithmetics.  Since
601.8Srillig * the type of the '&' expression is 'pointer to struct s', adding a constant
611.8Srillig * would rather be interpreted as adding 'constant * sizeof(struct s)', and
621.8Srillig * to access a member, the pointer to 'struct s' would need to be converted
631.8Srillig * to 'pointer of byte' first, then adding the offset 8, then converting the
641.8Srillig * pointer to the target type 'pointer to short'.
651.8Srillig *
661.8Srillig * Lint uses the simpler representation, saving a few conversions on the way.
671.8Srillig * Without this pre-multiplied representation, the below code would generate
681.8Srillig * warnings about out-of-bounds array access, starting with offset_1.
691.8Srillig */
701.6Srilligstruct s {
711.6Srillig	char offset_0;
721.6Srillig	char offset_1;
731.6Srillig	int offset_4;
741.6Srillig	short offset_8;
751.6Srillig	char offset_10;
761.6Srillig};
771.6Srillig
781.6Srilligstruct s
791.6Srilligs_init(void)
801.6Srillig{
811.6Srillig	struct s s[1];
821.6Srillig	s->offset_0 = 1;
831.6Srillig	s->offset_1 = 2;
841.6Srillig	s->offset_4 = 3;
851.6Srillig	s->offset_8 = 4;
861.6Srillig	s->offset_10 = 5;
871.6Srillig	return s[0];
881.6Srillig}
89