Module Name: src Committed By: rillig Date: Sun Mar 3 00:50:42 UTC 2024
Modified Files: src/distrib/sets/lists/tests: mi src/tests/usr.bin/xlint/lint1: msg_360.c msg_361.c msg_366.c msg_374.c msg_375.c msg_376.c t_usage.sh src/usr.bin/xlint/lint1: cksnprintb.c err.c externs1.h tree.c Added Files: src/tests/usr.bin/xlint/lint1: msg_377.c msg_378.c Log Message: lint: check for unreachable bits and fields in snprintb formats While here, clean up a few existing checks. To generate a diff of this commit: cvs rdiff -u -r1.1308 -r1.1309 src/distrib/sets/lists/tests/mi cvs rdiff -u -r1.1 -r1.2 src/tests/usr.bin/xlint/lint1/msg_360.c \ src/tests/usr.bin/xlint/lint1/msg_361.c \ src/tests/usr.bin/xlint/lint1/msg_366.c \ src/tests/usr.bin/xlint/lint1/msg_374.c \ src/tests/usr.bin/xlint/lint1/msg_376.c cvs rdiff -u -r1.2 -r1.3 src/tests/usr.bin/xlint/lint1/msg_375.c cvs rdiff -u -r0 -r1.1 src/tests/usr.bin/xlint/lint1/msg_377.c \ src/tests/usr.bin/xlint/lint1/msg_378.c cvs rdiff -u -r1.17 -r1.18 src/tests/usr.bin/xlint/lint1/t_usage.sh cvs rdiff -u -r1.3 -r1.4 src/usr.bin/xlint/lint1/cksnprintb.c cvs rdiff -u -r1.228 -r1.229 src/usr.bin/xlint/lint1/err.c cvs rdiff -u -r1.217 -r1.218 src/usr.bin/xlint/lint1/externs1.h cvs rdiff -u -r1.607 -r1.608 src/usr.bin/xlint/lint1/tree.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/tests/mi diff -u src/distrib/sets/lists/tests/mi:1.1308 src/distrib/sets/lists/tests/mi:1.1309 --- src/distrib/sets/lists/tests/mi:1.1308 Sat Mar 2 11:56:37 2024 +++ src/distrib/sets/lists/tests/mi Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1308 2024/03/02 11:56:37 rillig Exp $ +# $NetBSD: mi,v 1.1309 2024/03/03 00:50:41 rillig Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -7491,6 +7491,8 @@ ./usr/tests/usr.bin/xlint/lint1/msg_374.c tests-usr.bin-tests compattestfile,atf ./usr/tests/usr.bin/xlint/lint1/msg_375.c tests-usr.bin-tests compattestfile,atf ./usr/tests/usr.bin/xlint/lint1/msg_376.c tests-usr.bin-tests compattestfile,atf +./usr/tests/usr.bin/xlint/lint1/msg_377.c tests-usr.bin-tests compattestfile,atf +./usr/tests/usr.bin/xlint/lint1/msg_378.c tests-usr.bin-tests compattestfile,atf ./usr/tests/usr.bin/xlint/lint1/op_colon.c tests-usr.bin-tests compattestfile,atf ./usr/tests/usr.bin/xlint/lint1/op_colon.exp tests-obsolete obsolete,atf ./usr/tests/usr.bin/xlint/lint1/op_shl_lp64.c tests-usr.bin-tests compattestfile,atf Index: src/tests/usr.bin/xlint/lint1/msg_360.c diff -u src/tests/usr.bin/xlint/lint1/msg_360.c:1.1 src/tests/usr.bin/xlint/lint1/msg_360.c:1.2 --- src/tests/usr.bin/xlint/lint1/msg_360.c:1.1 Fri Mar 1 19:39:28 2024 +++ src/tests/usr.bin/xlint/lint1/msg_360.c Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: msg_360.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */ +/* $NetBSD: msg_360.c,v 1.2 2024/03/03 00:50:41 rillig Exp $ */ # 3 "msg_360.c" // Test for message: missing new-style number base after '\177' [360] @@ -23,6 +23,6 @@ new_style_number_base(void) /* expect+1: warning: missing new-style number base after '\177' [360] */ snprintb(buf, sizeof(buf), "\177", 0); - /* expect+1: warning: number base '\002' is 2, should be 8, 10 or 16 [361] */ + /* expect+1: warning: number base '\002' is 2, must be 8, 10 or 16 [361] */ snprintb(buf, sizeof(buf), "\177\002", 0); } Index: src/tests/usr.bin/xlint/lint1/msg_361.c diff -u src/tests/usr.bin/xlint/lint1/msg_361.c:1.1 src/tests/usr.bin/xlint/lint1/msg_361.c:1.2 --- src/tests/usr.bin/xlint/lint1/msg_361.c:1.1 Fri Mar 1 19:39:28 2024 +++ src/tests/usr.bin/xlint/lint1/msg_361.c Sun Mar 3 00:50:41 2024 @@ -1,7 +1,7 @@ -/* $NetBSD: msg_361.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */ +/* $NetBSD: msg_361.c,v 1.2 2024/03/03 00:50:41 rillig Exp $ */ # 3 "msg_361.c" -// Test for message: number base '%.*s' is %ju, should be 8, 10 or 16 [361] +// Test for message: number base '%.*s' is %ju, must be 8, 10 or 16 [361] /* * The first or second character of the snprintb format specifies the number @@ -22,12 +22,12 @@ old_style_number_base(void) /* expect+1: warning: missing new-style '\177' or old-style number base [359] */ snprintb(buf, sizeof(buf), "", 0); - /* expect+1: warning: number base '\002' is 2, should be 8, 10 or 16 [361] */ + /* expect+1: warning: number base '\002' is 2, must be 8, 10 or 16 [361] */ snprintb(buf, sizeof(buf), "\002", 0); snprintb(buf, sizeof(buf), "\010", 0); snprintb(buf, sizeof(buf), "\n", 0); snprintb(buf, sizeof(buf), "\020", 0); - /* expect+1: warning: number base '\014' is 12, should be 8, 10 or 16 [361] */ + /* expect+1: warning: number base '\014' is 12, must be 8, 10 or 16 [361] */ snprintb(buf, sizeof(buf), "" "\014" "", 0); snprintb(buf, sizeof(buf), "" "\020" "", 0); } @@ -39,14 +39,14 @@ new_style_number_base(void) /* expect+1: warning: missing new-style number base after '\177' [360] */ snprintb(buf, sizeof(buf), "\177", 0); - /* expect+1: warning: number base '\0' is 0, should be 8, 10 or 16 [361] */ + /* expect+1: warning: number base '\0' is 0, must be 8, 10 or 16 [361] */ snprintb(buf, sizeof(buf), "\177\0", 0); - /* expect+1: warning: number base '\002' is 2, should be 8, 10 or 16 [361] */ + /* expect+1: warning: number base '\002' is 2, must be 8, 10 or 16 [361] */ snprintb(buf, sizeof(buf), "\177\002", 0); snprintb(buf, sizeof(buf), "\177\010", 0); snprintb(buf, sizeof(buf), "\177\n", 0); snprintb(buf, sizeof(buf), "\177\020", 0); - /* expect+1: warning: number base '\014' is 12, should be 8, 10 or 16 [361] */ + /* expect+1: warning: number base '\014' is 12, must be 8, 10 or 16 [361] */ snprintb(buf, sizeof(buf), "" "\177\014" "", 0); snprintb(buf, sizeof(buf), "" "\177\020" "", 0); } Index: src/tests/usr.bin/xlint/lint1/msg_366.c diff -u src/tests/usr.bin/xlint/lint1/msg_366.c:1.1 src/tests/usr.bin/xlint/lint1/msg_366.c:1.2 --- src/tests/usr.bin/xlint/lint1/msg_366.c:1.1 Fri Mar 1 19:39:28 2024 +++ src/tests/usr.bin/xlint/lint1/msg_366.c Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: msg_366.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */ +/* $NetBSD: msg_366.c,v 1.2 2024/03/03 00:50:41 rillig Exp $ */ # 3 "msg_366.c" // Test for message: missing '\0' at the end of '%.*s' [366] @@ -24,7 +24,7 @@ example(unsigned u32) { char buf[64]; - /* expect+4: warning: unknown directive '\0' [374] */ + /* expect+4: warning: redundant '\0' at the end of new-style format [377] */ snprintb(buf, sizeof(buf), "\177\020" "\0", Index: src/tests/usr.bin/xlint/lint1/msg_374.c diff -u src/tests/usr.bin/xlint/lint1/msg_374.c:1.1 src/tests/usr.bin/xlint/lint1/msg_374.c:1.2 --- src/tests/usr.bin/xlint/lint1/msg_374.c:1.1 Fri Mar 1 19:39:29 2024 +++ src/tests/usr.bin/xlint/lint1/msg_374.c Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: msg_374.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */ +/* $NetBSD: msg_374.c,v 1.2 2024/03/03 00:50:41 rillig Exp $ */ # 3 "msg_374.c" // Test for message: unknown directive '%.*s' [374] @@ -31,4 +31,11 @@ example(uint64_t u64) "\177\020" "\00012345\0", u64); + + /* expect+5: warning: redundant '\0' at the end of new-style format [377] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\00012345\0" + "\0", + u64); } Index: src/tests/usr.bin/xlint/lint1/msg_376.c diff -u src/tests/usr.bin/xlint/lint1/msg_376.c:1.1 src/tests/usr.bin/xlint/lint1/msg_376.c:1.2 --- src/tests/usr.bin/xlint/lint1/msg_376.c:1.1 Sat Mar 2 11:56:37 2024 +++ src/tests/usr.bin/xlint/lint1/msg_376.c Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: msg_376.c,v 1.1 2024/03/02 11:56:37 rillig Exp $ */ +/* $NetBSD: msg_376.c,v 1.2 2024/03/03 00:50:41 rillig Exp $ */ # 3 "msg_376.c" // Test for message: '%.*s' overlaps earlier '%.*s' on bit %u [376] @@ -32,7 +32,7 @@ example(unsigned u32, uint64_t u64) "\x21oob", u32); - // In the new-style format, bit positions are 1-based. + // In the new-style format, bit positions are 0-based. /* expect+10: warning: 'b\x00lsb\0' overlaps earlier 'b\000lsb\0' on bit 0 [376] */ /* expect+9: warning: 'b\x3fmsb\0' overlaps earlier 'b\077msb\0' on bit 63 [376] */ /* expect+8: warning: bit position '\x40' (64) in 'b\x40oob\0' out of range 0..63 [371] */ Index: src/tests/usr.bin/xlint/lint1/msg_375.c diff -u src/tests/usr.bin/xlint/lint1/msg_375.c:1.2 src/tests/usr.bin/xlint/lint1/msg_375.c:1.3 --- src/tests/usr.bin/xlint/lint1/msg_375.c:1.2 Sat Mar 2 11:56:37 2024 +++ src/tests/usr.bin/xlint/lint1/msg_375.c Sun Mar 3 00:50:41 2024 @@ -1,7 +1,7 @@ -/* $NetBSD: msg_375.c,v 1.2 2024/03/02 11:56:37 rillig Exp $ */ +/* $NetBSD: msg_375.c,v 1.3 2024/03/03 00:50:41 rillig Exp $ */ # 3 "msg_375.c" -// Test for message: comparison value '%.*s' (%ju) exceeds field width %ju [375] +// Test for message: comparison value '%.*s' (%ju) exceeds maximum field value %ju [375] /* * When a bit field can take the values 0 to 15, there is no point comparing @@ -20,10 +20,10 @@ example(uint64_t u64) { char buf[64]; - /* expect+14: warning: comparison value '\020' (16) exceeds field width 4 [375] */ - /* expect+13: warning: comparison value '\377' (255) exceeds field width 4 [375] */ - /* expect+12: warning: comparison value '\020' (16) exceeds field width 4 [375] */ - /* expect+11: warning: comparison value '\377' (255) exceeds field width 4 [375] */ + /* expect+14: warning: comparison value '\020' (16) exceeds maximum field value 15 [375] */ + /* expect+13: warning: comparison value '\377' (255) exceeds maximum field value 15 [375] */ + /* expect+12: warning: comparison value '\020' (16) exceeds maximum field value 15 [375] */ + /* expect+11: warning: comparison value '\377' (255) exceeds maximum field value 15 [375] */ snprintb(buf, sizeof(buf), "\177\020" "f\000\004low\0" Index: src/tests/usr.bin/xlint/lint1/t_usage.sh diff -u src/tests/usr.bin/xlint/lint1/t_usage.sh:1.17 src/tests/usr.bin/xlint/lint1/t_usage.sh:1.18 --- src/tests/usr.bin/xlint/lint1/t_usage.sh:1.17 Sat Mar 2 11:56:37 2024 +++ src/tests/usr.bin/xlint/lint1/t_usage.sh Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -# $NetBSD: t_usage.sh,v 1.17 2024/03/02 11:56:37 rillig Exp $ +# $NetBSD: t_usage.sh,v 1.18 2024/03/03 00:50:41 rillig Exp $ # # Copyright (c) 2023 The NetBSD Foundation, Inc. # All rights reserved. @@ -39,13 +39,13 @@ suppress_messages_body() # The largest known message. atf_check \ - "$lint1" -X 376 code.c /dev/null + "$lint1" -X 378 code.c /dev/null # Larger than the largest known message. atf_check \ -s 'exit:1' \ - -e "inline:lint1: invalid message ID '377'\n" \ - "$lint1" -X 377 code.c /dev/null + -e "inline:lint1: invalid message ID '379'\n" \ + "$lint1" -X 379 code.c /dev/null # Whitespace is not allowed before a message ID. atf_check \ Index: src/usr.bin/xlint/lint1/cksnprintb.c diff -u src/usr.bin/xlint/lint1/cksnprintb.c:1.3 src/usr.bin/xlint/lint1/cksnprintb.c:1.4 --- src/usr.bin/xlint/lint1/cksnprintb.c:1.3 Sat Mar 2 11:56:37 2024 +++ src/usr.bin/xlint/lint1/cksnprintb.c Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: cksnprintb.c,v 1.3 2024/03/02 11:56:37 rillig Exp $ */ +/* $NetBSD: cksnprintb.c,v 1.4 2024/03/03 00:50:41 rillig Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) -__RCSID("$NetBSD: cksnprintb.c,v 1.3 2024/03/02 11:56:37 rillig Exp $"); +__RCSID("$NetBSD: cksnprintb.c,v 1.4 2024/03/03 00:50:41 rillig Exp $"); #endif #include <stdbool.h> @@ -46,10 +46,11 @@ __RCSID("$NetBSD: cksnprintb.c,v 1.3 202 typedef struct { bool new_style; const buffer *fmt; + const tnode_t *value; uint64_t field_width; uint64_t covered; - size_t covered_start[64]; - size_t covered_end[64]; + unsigned covered_start[64]; + unsigned covered_end[64]; } checker; static bool @@ -133,9 +134,9 @@ static void check_overlap(checker *ck, uint64_t dir_lsb, uint64_t width, size_t start, size_t end) { - if (dir_lsb >= 64 || width == 0 || width > 64) - return; unsigned lsb = (unsigned)(ck->new_style ? dir_lsb : dir_lsb - 1); + if (lsb >= 64 || width == 0 || width > 64) + return; uint64_t field_mask = value_bits((unsigned)width) << lsb; uint64_t overlap = ck->covered & field_mask; @@ -158,12 +159,27 @@ done: ck->covered |= field_mask; for (unsigned i = lsb; i < 64; i++) { if (field_mask & bit(i)) { - ck->covered_start[i] = start; - ck->covered_end[i] = end; + ck->covered_start[i] = (unsigned)start; + ck->covered_end[i] = (unsigned)end; } } } +static void +check_reachable(checker *ck, uint64_t dir_lsb, uint64_t width, + size_t start, size_t end) +{ + unsigned lsb = (unsigned)(ck->new_style ? dir_lsb : dir_lsb - 1); + if (lsb >= 64 || width == 0 || width > 64) + return; + + uint64_t field_mask = value_bits((unsigned)width) << lsb; + if (!(possible_bits(ck->value) & field_mask)) { + /* directive '%.*s' is unreachable by input value */ + warning(378, (int)(end - start), ck->fmt->data + start); + } +} + static bool check_directive(const buffer *fmt, quoted_iterator *it, bool new_style, checker *ck) @@ -177,7 +193,7 @@ check_directive(const buffer *fmt, quote || dir.value == 'b' || dir.value == 'f' || dir.value == 'F'; if (has_bit && new_style && !quoted_next(fmt, it)) { /* missing bit position after '%.*s' */ - warning(364, len(dir), start(dir, fmt)); + warning(364, range(dir, *it), start(dir, fmt)); return false; } /* LINTED 86 "automatic 'bit' hides external declaration" */ @@ -187,7 +203,7 @@ check_directive(const buffer *fmt, quote && (dir.value == 'f' || dir.value == 'F'); if (has_width && !quoted_next(fmt, it)) { /* missing field width after '%.*s' */ - warning(365, range(dir, bit), start(dir, fmt)); + warning(365, range(dir, *it), start(dir, fmt)); return false; } quoted_iterator width = *it; @@ -196,7 +212,7 @@ check_directive(const buffer *fmt, quote && (dir.value == '=' || dir.value == ':'); if (has_cmp && !quoted_next(fmt, it)) { /* missing comparison value after directive '%.*s' */ - warning(368, range(dir, bit), start(dir, fmt)); + warning(368, range(dir, *it), start(dir, fmt)); return false; } quoted_iterator cmp = *it; @@ -208,6 +224,15 @@ check_directive(const buffer *fmt, quote return false; } + if (new_style && dir.value == '\0') { + quoted_iterator end = *it; + if (!quoted_next(fmt, &end)) { + /* redundant '\0' at the end of new-style format */ + warning(377); + return false; + } + } + if (!has_bit && !has_cmp && !has_default) { /* unknown directive '%.*s' */ warning(374, len(dir), start(dir, fmt)); @@ -288,14 +313,18 @@ check_directive(const buffer *fmt, quote } if (has_cmp && ck->field_width < 64 && cmp.value & ~(uint64_t)0 << ck->field_width) { - /* comparison value '%.*s' (%ju) exceeds field width %ju */ + /* comparison value '%.*s' (%ju) exceeds maximum field ... */ warning(375, len(cmp), start(cmp, fmt), val(cmp), - (uintmax_t)ck->field_width); + (uintmax_t)value_bits((unsigned)ck->field_width)); } if (has_bit) { uint64_t w = has_width ? width.value : 1; check_overlap(ck, bit.value, w, dir.start, it->i); } + if (has_bit) { + uint64_t w = has_width ? width.value : 1; + check_reachable(ck, bit.value, w, dir.start, it->i); + } if (descr.i == prev.i && dir.value != 'F') { /* empty description in '%.*s' */ warning(367, range(dir, *it), start(dir, fmt)); @@ -327,7 +356,7 @@ check_snprintb(const tnode_t *expr) return; } if (it.value != 8 && it.value != 10 && it.value != 16) { - /* number base '%.*s' is %ju, should be 8, 10 or 16 */ + /* number base '%.*s' is %ju, must be 8, 10 or 16 */ warning(361, len(it), start(it, fmt), val(it)); return; } @@ -335,6 +364,7 @@ check_snprintb(const tnode_t *expr) checker ck = { .new_style = new_style, .fmt = fmt, + .value = value, .field_width = 64, }; while (check_directive(fmt, &it, new_style, &ck)) Index: src/usr.bin/xlint/lint1/err.c diff -u src/usr.bin/xlint/lint1/err.c:1.228 src/usr.bin/xlint/lint1/err.c:1.229 --- src/usr.bin/xlint/lint1/err.c:1.228 Sat Mar 2 11:56:37 2024 +++ src/usr.bin/xlint/lint1/err.c Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: err.c,v 1.228 2024/03/02 11:56:37 rillig Exp $ */ +/* $NetBSD: err.c,v 1.229 2024/03/03 00:50:41 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -37,7 +37,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) -__RCSID("$NetBSD: err.c,v 1.228 2024/03/02 11:56:37 rillig Exp $"); +__RCSID("$NetBSD: err.c,v 1.229 2024/03/03 00:50:41 rillig Exp $"); #endif #include <limits.h> @@ -416,7 +416,7 @@ static const char *const msgs[] = { "hex escape '%.*s' has more than 2 digits", // 358 "missing new-style '\\177' or old-style number base", // 359 "missing new-style number base after '\\177'", // 360 - "number base '%.*s' is %ju, should be 8, 10 or 16", // 361 + "number base '%.*s' is %ju, must be 8, 10 or 16", // 361 "old-style format contains '\\0'", // 362 "non-printing character '%.*s' in description '%.*s'", // 363 "missing bit position after '%.*s'", // 364 @@ -430,8 +430,10 @@ static const char *const msgs[] = { "field width '%.*s' (%ju) in '%.*s' out of range 0..%u", // 372 "bit field end %ju in '%.*s' out of range 0..64", // 373 "unknown directive '%.*s'", // 374 - "comparison value '%.*s' (%ju) exceeds field width %ju", // 375 + "comparison value '%.*s' (%ju) exceeds maximum field value %ju", // 375 "'%.*s' overlaps earlier '%.*s' on bit %u", // 376 + "redundant '\\0' at the end of new-style format", // 377 + "directive '%.*s' is unreachable by input value", // 378 }; static bool is_suppressed[sizeof(msgs) / sizeof(msgs[0])]; Index: src/usr.bin/xlint/lint1/externs1.h diff -u src/usr.bin/xlint/lint1/externs1.h:1.217 src/usr.bin/xlint/lint1/externs1.h:1.218 --- src/usr.bin/xlint/lint1/externs1.h:1.217 Fri Mar 1 19:39:28 2024 +++ src/usr.bin/xlint/lint1/externs1.h Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: externs1.h,v 1.217 2024/03/01 19:39:28 rillig Exp $ */ +/* $NetBSD: externs1.h,v 1.218 2024/03/03 00:50:41 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -301,6 +301,7 @@ bool constant_addr(const tnode_t *, cons buffer *cat_strings(buffer *, buffer *); unsigned int type_size_in_bits(const type_t *); sym_t *find_member(const struct_or_union *, const char *); +uint64_t possible_bits(const tnode_t *); void begin_statement_expr(void); void do_statement_expr(tnode_t *); Index: src/usr.bin/xlint/lint1/tree.c diff -u src/usr.bin/xlint/lint1/tree.c:1.607 src/usr.bin/xlint/lint1/tree.c:1.608 --- src/usr.bin/xlint/lint1/tree.c:1.607 Fri Mar 1 21:52:48 2024 +++ src/usr.bin/xlint/lint1/tree.c Sun Mar 3 00:50:41 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: tree.c,v 1.607 2024/03/01 21:52:48 rillig Exp $ */ +/* $NetBSD: tree.c,v 1.608 2024/03/03 00:50:41 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -37,7 +37,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) -__RCSID("$NetBSD: tree.c,v 1.607 2024/03/01 21:52:48 rillig Exp $"); +__RCSID("$NetBSD: tree.c,v 1.608 2024/03/03 00:50:41 rillig Exp $"); #endif #include <float.h> @@ -317,6 +317,12 @@ ic_expr(const tnode_t *tn) } } +uint64_t +possible_bits(const tnode_t *tn) +{ + return ~ic_expr(tn).bclr; +} + /* Build 'pointer to tp', 'array of tp' or 'function returning tp'. */ type_t * block_derive_type(type_t *tp, tspec_t t) Added files: Index: src/tests/usr.bin/xlint/lint1/msg_377.c diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_377.c:1.1 --- /dev/null Sun Mar 3 00:50:42 2024 +++ src/tests/usr.bin/xlint/lint1/msg_377.c Sun Mar 3 00:50:41 2024 @@ -0,0 +1,38 @@ +/* $NetBSD: msg_377.c,v 1.1 2024/03/03 00:50:41 rillig Exp $ */ +# 3 "msg_377.c" + +// Test for message: redundant '\0' at the end of new-style format [377] + +/* + * Each directive in the new-style format ends with a '\0'. The final '\0' + * that ends the whole format is provided implicitly by the compiler as part + * of the string literal. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char*, size_t, const char*, uint64_t); + +void +example(unsigned u32, uint64_t u64) +{ + char buf[64]; + + /* expect+6: warning: old-style format contains '\0' [362] */ + /* expect+5: warning: empty description in '\0' [367] */ + snprintb(buf, sizeof(buf), + "\020" + "\005bit" + "\0", + u32); + + /* expect+5: warning: redundant '\0' at the end of new-style format [377] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\005bit\0" + "\0", + u64); +} Index: src/tests/usr.bin/xlint/lint1/msg_378.c diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_378.c:1.1 --- /dev/null Sun Mar 3 00:50:42 2024 +++ src/tests/usr.bin/xlint/lint1/msg_378.c Sun Mar 3 00:50:41 2024 @@ -0,0 +1,52 @@ +/* $NetBSD: msg_378.c,v 1.1 2024/03/03 00:50:41 rillig Exp $ */ +# 3 "msg_378.c" + +// Test for message: directive '%.*s' is unreachable by input value [378] + +/* + * The typical use case of snprintb is to have a format that is specifically + * tailored to a particular input value. Often, a format is only used in a + * single place. Therefore, bits that are unreachable are redundant and may + * hint at typos. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char*, size_t, const char*, uint64_t); + +void +example(unsigned u32, uint64_t u64) +{ + char buf[64]; + + /* expect+5: warning: directive '\040bit32' is unreachable by input value [378] */ + snprintb(buf, sizeof(buf), + "\020" + "\037bit31" + "\040bit32", + u32 >> 1); + + /* expect+5: warning: directive 'b\075bit61\0' is unreachable by input value [378] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\074bit60\0" + "b\075bit61\0", + u64 >> 3); + + /* expect+12: warning: directive 'b\000bit0\0' is unreachable by input value [378] */ + /* expect+11: warning: directive 'b\011bit9\0' is unreachable by input value [378] */ + /* expect+10: warning: directive 'f\017\002bits15-16\0' is unreachable by input value [378] */ + /* expect+9: warning: directive 'f\050\030bits40-63\0' is unreachable by input value [378] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\000bit0\0" + "b\010bit8\0" + "b\011bit9\0" + "f\012\002bits10-11\0" + "f\017\002bits15-16\0" + "f\050\030bits40-63\0", + (u32 & 0xaa55aa55) << 8); +}