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);
+}