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 8 void print_string(const char *); 9 void print_char(char); 10 11 void 12 example(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 34 void 35 array_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 */ 72 struct s { 73 char offset_0; 74 char offset_1; 75 int offset_4; 76 short offset_8; 77 char offset_10; 78 }; 79 80 struct s 81 s_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