/* $NetBSD: msg_168.c,v 1.13 2024/03/30 17:12:26 rillig Exp $ */ # 3 "msg_168.c" // Test for message: array subscript %ju cannot be > %d [168] /* lint1-extra-flags: -X 351 */ void print_string(const char *); void print_char(char); void example(void) { char buf[20] = {}; /* empty initializer is a GCC extension */ print_string(buf + 19); /* inside the array */ /* * It is valid to point at the end of the array, but reading a * character from there invokes undefined behavior. * * The pointer to the end of the array is typically used in (begin, * end) tuples. These are more common in C++ than in C though. */ print_string(buf + 20); print_string(buf + 21); /* undefined behavior, not detected */ print_char(buf[19]); /* expect+1: warning: array subscript 20 cannot be > 19 [168] */ print_char(buf[20]); } void array_with_c99_initializer(void) { static const char *const to_roman[] = { ['0'] = "undefined", ['5'] = "V", ['9'] = "IX" }; print_string(to_roman['9']); /* expect+1: warning: array subscript 58 cannot be > 57 [168] */ print_string(to_roman[':']); } /* * In its expression tree, lint represents pointer addition as 'ptr + off', * where 'off' is the offset in bytes, regardless of the pointer type. * * In the below code, the member 'offset_8' has type 'short', and the * expression 's->offset_8' is represented as '&s + 8', or more verbose: * * '+' type 'pointer to short' * '&' type 'pointer to struct s' * 'name' 's' with auto 'array[1] of struct s', lvalue * 'constant' type 'long', value 8 * * The constant 8 differs from the usual model of pointer arithmetics. Since * the type of the '&' expression is 'pointer to struct s', adding a constant * would rather be interpreted as adding 'constant * sizeof(struct s)', and * to access a member, the pointer to 'struct s' would need to be converted * to 'pointer of byte' first, then adding the offset 8, then converting the * pointer to the target type 'pointer to short'. * * Lint uses the simpler representation, saving a few conversions on the way. * Without this pre-multiplied representation, the below code would generate * warnings about out-of-bounds array access, starting with offset_1. */ struct s { char offset_0; char offset_1; int offset_4; short offset_8; char offset_10; }; struct s s_init(void) { struct s s[1]; s->offset_0 = 1; s->offset_1 = 2; s->offset_4 = 3; s->offset_8 = 4; s->offset_10 = 5; return s[0]; }