11.13Srillig/* $NetBSD: msg_168.c,v 1.13 2024/03/30 17:12:26 rillig Exp $ */ 21.1Srillig# 3 "msg_168.c" 31.1Srillig 41.13Srillig// Test for message: array subscript %ju cannot be > %d [168] 51.1Srillig 61.10Srillig/* lint1-extra-flags: -X 351 */ 71.10Srillig 81.2Srilligvoid print_string(const char *); 91.2Srilligvoid print_char(char); 101.2Srillig 111.2Srilligvoid 121.2Srilligexample(void) 131.2Srillig{ 141.4Srillig char buf[20] = {}; /* empty initializer is a GCC extension */ 151.2Srillig 161.2Srillig print_string(buf + 19); /* inside the array */ 171.2Srillig 181.2Srillig /* 191.2Srillig * It is valid to point at the end of the array, but reading a 201.2Srillig * character from there invokes undefined behavior. 211.2Srillig * 221.2Srillig * The pointer to the end of the array is typically used in (begin, 231.2Srillig * end) tuples. These are more common in C++ than in C though. 241.2Srillig */ 251.2Srillig print_string(buf + 20); 261.2Srillig 271.2Srillig print_string(buf + 21); /* undefined behavior, not detected */ 281.2Srillig 291.2Srillig print_char(buf[19]); 301.12Srillig /* expect+1: warning: array subscript 20 cannot be > 19 [168] */ 311.9Srillig print_char(buf[20]); 321.2Srillig} 331.3Srillig 341.3Srilligvoid 351.3Srilligarray_with_c99_initializer(void) 361.3Srillig{ 371.3Srillig static const char *const to_roman[] = { 381.3Srillig ['0'] = "undefined", 391.3Srillig ['5'] = "V", 401.3Srillig ['9'] = "IX" 411.3Srillig }; 421.3Srillig 431.5Srillig print_string(to_roman['9']); 441.12Srillig /* expect+1: warning: array subscript 58 cannot be > 57 [168] */ 451.9Srillig print_string(to_roman[':']); 461.3Srillig} 471.6Srillig 481.6Srillig 491.8Srillig/* 501.8Srillig * In its expression tree, lint represents pointer addition as 'ptr + off', 511.8Srillig * where 'off' is the offset in bytes, regardless of the pointer type. 521.8Srillig * 531.8Srillig * In the below code, the member 'offset_8' has type 'short', and the 541.8Srillig * expression 's->offset_8' is represented as '&s + 8', or more verbose: 551.8Srillig * 561.8Srillig * '+' type 'pointer to short' 571.8Srillig * '&' type 'pointer to struct s' 581.8Srillig * 'name' 's' with auto 'array[1] of struct s', lvalue 591.8Srillig * 'constant' type 'long', value 8 601.8Srillig * 611.8Srillig * The constant 8 differs from the usual model of pointer arithmetics. Since 621.8Srillig * the type of the '&' expression is 'pointer to struct s', adding a constant 631.8Srillig * would rather be interpreted as adding 'constant * sizeof(struct s)', and 641.8Srillig * to access a member, the pointer to 'struct s' would need to be converted 651.8Srillig * to 'pointer of byte' first, then adding the offset 8, then converting the 661.8Srillig * pointer to the target type 'pointer to short'. 671.8Srillig * 681.8Srillig * Lint uses the simpler representation, saving a few conversions on the way. 691.8Srillig * Without this pre-multiplied representation, the below code would generate 701.8Srillig * warnings about out-of-bounds array access, starting with offset_1. 711.8Srillig */ 721.6Srilligstruct s { 731.6Srillig char offset_0; 741.6Srillig char offset_1; 751.6Srillig int offset_4; 761.6Srillig short offset_8; 771.6Srillig char offset_10; 781.6Srillig}; 791.6Srillig 801.6Srilligstruct s 811.6Srilligs_init(void) 821.6Srillig{ 831.6Srillig struct s s[1]; 841.6Srillig s->offset_0 = 1; 851.6Srillig s->offset_1 = 2; 861.6Srillig s->offset_4 = 3; 871.6Srillig s->offset_8 = 4; 881.6Srillig s->offset_10 = 5; 891.6Srillig return s[0]; 901.6Srillig} 91