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 6 void print_string(const char *); 7 void print_char(char); 8 9 void 10 example(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 32 void 33 array_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 */ 70 struct s { 71 char offset_0; 72 char offset_1; 73 int offset_4; 74 short offset_8; 75 char offset_10; 76 }; 77 78 struct s 79 s_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