msg_168.c revision 1.8
11.8Srillig/*	$NetBSD: msg_168.c,v 1.8 2022/05/30 08:51:08 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.2Srillig	print_char(buf[20]);	/* expect: 168 */
291.2Srillig}
301.3Srillig
311.3Srilligvoid
321.3Srilligarray_with_c99_initializer(void)
331.3Srillig{
341.3Srillig	static const char *const to_roman[] = {
351.3Srillig	    ['0'] = "undefined",
361.3Srillig	    ['5'] = "V",
371.3Srillig	    ['9'] = "IX"
381.3Srillig	};
391.3Srillig
401.5Srillig	print_string(to_roman['9']);
411.3Srillig	print_string(to_roman[':']);	/* expect: 168 */
421.3Srillig}
431.6Srillig
441.6Srillig
451.8Srillig/*
461.8Srillig * In its expression tree, lint represents pointer addition as 'ptr + off',
471.8Srillig * where 'off' is the offset in bytes, regardless of the pointer type.
481.8Srillig *
491.8Srillig * In the below code, the member 'offset_8' has type 'short', and the
501.8Srillig * expression 's->offset_8' is represented as '&s + 8', or more verbose:
511.8Srillig *
521.8Srillig *	'+' type 'pointer to short'
531.8Srillig *		'&' type 'pointer to struct s'
541.8Srillig *			'name' 's' with auto 'array[1] of struct s', lvalue
551.8Srillig *		'constant' type 'long', value 8
561.8Srillig *
571.8Srillig * The constant 8 differs from the usual model of pointer arithmetics.  Since
581.8Srillig * the type of the '&' expression is 'pointer to struct s', adding a constant
591.8Srillig * would rather be interpreted as adding 'constant * sizeof(struct s)', and
601.8Srillig * to access a member, the pointer to 'struct s' would need to be converted
611.8Srillig * to 'pointer of byte' first, then adding the offset 8, then converting the
621.8Srillig * pointer to the target type 'pointer to short'.
631.8Srillig *
641.8Srillig * Lint uses the simpler representation, saving a few conversions on the way.
651.8Srillig * Without this pre-multiplied representation, the below code would generate
661.8Srillig * warnings about out-of-bounds array access, starting with offset_1.
671.8Srillig */
681.6Srilligstruct s {
691.6Srillig	char offset_0;
701.6Srillig	char offset_1;
711.6Srillig	int offset_4;
721.6Srillig	short offset_8;
731.6Srillig	char offset_10;
741.6Srillig};
751.6Srillig
761.6Srilligstruct s
771.6Srilligs_init(void)
781.6Srillig{
791.6Srillig	struct s s[1];
801.6Srillig	s->offset_0 = 1;
811.6Srillig	s->offset_1 = 2;
821.6Srillig	s->offset_4 = 3;
831.6Srillig	s->offset_8 = 4;
841.6Srillig	s->offset_10 = 5;
851.6Srillig	return s[0];
861.6Srillig}
87