Module Name: src
Committed By: rillig
Date: Sun Mar 3 13:09:23 UTC 2024
Modified Files:
src/tests/usr.bin/xlint/lint1: msg_358.c msg_362.c msg_363.c msg_372.c
msg_373.c msg_374.c msg_377.c
src/usr.bin/xlint/lint1: cksnprintb.c err.c
Log Message:
lint: warn about escaped snprintb directive
Repurpose message 362, as the previous version was redundant since null
bytes in old-style formats are already covered by message 371 (bit
position out of range) and 377 (redundant '\0' at the end).
To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/tests/usr.bin/xlint/lint1/msg_358.c \
src/tests/usr.bin/xlint/lint1/msg_362.c
cvs rdiff -u -r1.2 -r1.3 src/tests/usr.bin/xlint/lint1/msg_363.c \
src/tests/usr.bin/xlint/lint1/msg_372.c \
src/tests/usr.bin/xlint/lint1/msg_373.c \
src/tests/usr.bin/xlint/lint1/msg_377.c
cvs rdiff -u -r1.3 -r1.4 src/tests/usr.bin/xlint/lint1/msg_374.c
cvs rdiff -u -r1.5 -r1.6 src/usr.bin/xlint/lint1/cksnprintb.c
cvs rdiff -u -r1.230 -r1.231 src/usr.bin/xlint/lint1/err.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/tests/usr.bin/xlint/lint1/msg_358.c
diff -u src/tests/usr.bin/xlint/lint1/msg_358.c:1.1 src/tests/usr.bin/xlint/lint1/msg_358.c:1.2
--- src/tests/usr.bin/xlint/lint1/msg_358.c:1.1 Fri Mar 1 19:39:28 2024
+++ src/tests/usr.bin/xlint/lint1/msg_358.c Sun Mar 3 13:09:23 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: msg_358.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+/* $NetBSD: msg_358.c,v 1.2 2024/03/03 13:09:23 rillig Exp $ */
# 3 "msg_358.c"
// Test for message: hex escape '%.*s' has more than 2 digits [358]
@@ -49,4 +49,13 @@ examples(unsigned u32, uint64_t u64)
snprintb(buf, sizeof(buf),
"\177\020f\x00\x02bit\0",
u64);
+
+ // In this example from the snprintb manual page, the descriptions
+ // that start with a hexadecimal digit must be separated from the
+ // hexadecimal escape sequence for the bit position.
+ snprintb(buf, sizeof(buf),
+ "\20\x10NOTBOOT\x0f" "FPP\x0eSDVMA\x0cVIDEO"
+ "\x0bLORES\x0a" "FPA\x09" "DIAG\x07" "CACHE"
+ "\x06IOCACHE\x05LOOPBACK\x04" "DBGCACHE",
+ u32);
}
Index: src/tests/usr.bin/xlint/lint1/msg_362.c
diff -u src/tests/usr.bin/xlint/lint1/msg_362.c:1.1 src/tests/usr.bin/xlint/lint1/msg_362.c:1.2
--- src/tests/usr.bin/xlint/lint1/msg_362.c:1.1 Fri Mar 1 19:39:28 2024
+++ src/tests/usr.bin/xlint/lint1/msg_362.c Sun Mar 3 13:09:23 2024
@@ -1,11 +1,11 @@
-/* $NetBSD: msg_362.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+/* $NetBSD: msg_362.c,v 1.2 2024/03/03 13:09:23 rillig Exp $ */
# 3 "msg_362.c"
-// Test for message: old-style format contains '\0' [362]
+// Test for message: directive '%.*s' should not be escaped [362]
/*
- * The old-style format uses 1-based bit positions, from 1 up to 32.
- * A null character would prematurely end the format argument.
+ * Since the characters used for the directive type are chosen to be easily
+ * readable, it doesn't make sense to obfuscate them.
*/
/* lint1-extra-flags: -X 351 */
@@ -20,9 +20,14 @@ example(unsigned u32)
{
char buf[64];
- /* expect+1: warning: bit position '\000' (0) in '\000lsb' out of range 1..32 [371] */
- snprintb(buf, sizeof(buf), "\020\000lsb\037msb", u32);
- /* expect+2: warning: old-style format contains '\0' [362] */
- /* expect+1: warning: bit position '\000' (0) in '\000lsb' out of range 1..32 [371] */
- snprintb(buf, sizeof(buf), "\020\037msb\000lsb", u32);
+ /* expect+9: warning: directive '\142' should not be escaped [362] */
+ /* expect+8: warning: bit position 'o' in '\142old-style-lsb\0' should be escaped as octal or hex [369] */
+ /* expect+7: warning: bit position 'o' (111) in '\142old-style-lsb\0' out of range 0..63 [371] */
+ /* expect+6: warning: unknown directive '\001', must be one of 'bfF=:*' [374] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "\142old-style-lsb\0"
+ "\001old-style-lsb\0"
+ "\142\000old-style-lsb\0",
+ u32);
}
Index: src/tests/usr.bin/xlint/lint1/msg_363.c
diff -u src/tests/usr.bin/xlint/lint1/msg_363.c:1.2 src/tests/usr.bin/xlint/lint1/msg_363.c:1.3
--- src/tests/usr.bin/xlint/lint1/msg_363.c:1.2 Sun Mar 3 10:27:18 2024
+++ src/tests/usr.bin/xlint/lint1/msg_363.c Sun Mar 3 13:09:23 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: msg_363.c,v 1.2 2024/03/03 10:27:18 rillig Exp $ */
+/* $NetBSD: msg_363.c,v 1.3 2024/03/03 13:09:23 rillig Exp $ */
# 3 "msg_363.c"
// Test for message: non-printing character '%.*s' in description '%.*s' [363]
@@ -29,9 +29,7 @@ old_style_description(unsigned u32)
"\001non\tprint\nable\377",
u32);
- /* expect+8: warning: old-style format contains '\0' [362] */
- /* expect+7: warning: bit position '\000' (0) in '\000print' out of range 1..32 [371] */
- /* expect+6: warning: old-style format contains '\0' [362] */
+ /* expect+6: warning: bit position '\000' (0) in '\000print' out of range 1..32 [371] */
/* expect+5: warning: bit position '\n' in '\nable' should be escaped as octal or hex [369] */
/* expect+4: warning: redundant '\0' at the end of the format [377] */
snprintb(buf, sizeof(buf),
Index: src/tests/usr.bin/xlint/lint1/msg_372.c
diff -u src/tests/usr.bin/xlint/lint1/msg_372.c:1.2 src/tests/usr.bin/xlint/lint1/msg_372.c:1.3
--- src/tests/usr.bin/xlint/lint1/msg_372.c:1.2 Sat Mar 2 11:56:37 2024
+++ src/tests/usr.bin/xlint/lint1/msg_372.c Sun Mar 3 13:09:23 2024
@@ -1,7 +1,7 @@
-/* $NetBSD: msg_372.c,v 1.2 2024/03/02 11:56:37 rillig Exp $ */
+/* $NetBSD: msg_372.c,v 1.3 2024/03/03 13:09:23 rillig Exp $ */
# 3 "msg_372.c"
-// Test for message: field width '%.*s' (%ju) in '%.*s' out of range 0..%u [372]
+// Test for message: field width '%.*s' (%ju) in '%.*s' out of range 0..64 [372]
/*
* In new-style formats, the width of a bit-field must be between 0 (an empty
Index: src/tests/usr.bin/xlint/lint1/msg_373.c
diff -u src/tests/usr.bin/xlint/lint1/msg_373.c:1.2 src/tests/usr.bin/xlint/lint1/msg_373.c:1.3
--- src/tests/usr.bin/xlint/lint1/msg_373.c:1.2 Sat Mar 2 11:56:37 2024
+++ src/tests/usr.bin/xlint/lint1/msg_373.c Sun Mar 3 13:09:23 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: msg_373.c,v 1.2 2024/03/02 11:56:37 rillig Exp $ */
+/* $NetBSD: msg_373.c,v 1.3 2024/03/03 13:09:23 rillig Exp $ */
# 3 "msg_373.c"
// Test for message: bit field end %ju in '%.*s' out of range 0..64 [373]
@@ -34,4 +34,11 @@ example(uint64_t u64)
"f\001\100oob64\0"
"f\010\377oob64\0",
u64);
+
+ /* expect+5: warning: bit position '\377' (255) in 'f\377\002wrap-around\0' out of range 0..63 [371] */
+ /* expect+4: warning: bit field end 257 in 'f\377\002wrap-around\0' out of range 0..64 [373] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\377\002wrap-around\0",
+ u64);
}
Index: src/tests/usr.bin/xlint/lint1/msg_377.c
diff -u src/tests/usr.bin/xlint/lint1/msg_377.c:1.2 src/tests/usr.bin/xlint/lint1/msg_377.c:1.3
--- src/tests/usr.bin/xlint/lint1/msg_377.c:1.2 Sun Mar 3 10:27:18 2024
+++ src/tests/usr.bin/xlint/lint1/msg_377.c Sun Mar 3 13:09:23 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: msg_377.c,v 1.2 2024/03/03 10:27:18 rillig Exp $ */
+/* $NetBSD: msg_377.c,v 1.3 2024/03/03 13:09:23 rillig Exp $ */
# 3 "msg_377.c"
// Test for message: redundant '\0' at the end of the format [377]
@@ -23,8 +23,6 @@ example(unsigned u32, uint64_t u64)
{
char buf[64];
- /* expect+9: warning: old-style format contains '\0' [362] */
- /* expect+8: warning: old-style format contains '\0' [362] */
/* expect+7: warning: bit position '\000' (0) in '\000out-of-range' out of range 1..32 [371] */
/* expect+6: warning: redundant '\0' at the end of the format [377] */
snprintb(buf, sizeof(buf),
Index: src/tests/usr.bin/xlint/lint1/msg_374.c
diff -u src/tests/usr.bin/xlint/lint1/msg_374.c:1.3 src/tests/usr.bin/xlint/lint1/msg_374.c:1.4
--- src/tests/usr.bin/xlint/lint1/msg_374.c:1.3 Sun Mar 3 10:27:18 2024
+++ src/tests/usr.bin/xlint/lint1/msg_374.c Sun Mar 3 13:09:23 2024
@@ -1,7 +1,7 @@
-/* $NetBSD: msg_374.c,v 1.3 2024/03/03 10:27:18 rillig Exp $ */
+/* $NetBSD: msg_374.c,v 1.4 2024/03/03 13:09:23 rillig Exp $ */
# 3 "msg_374.c"
-// Test for message: unknown directive '%.*s' [374]
+// Test for message: unknown directive '%.*s', must be one of 'bfF=:*' [374]
/*
* In the new-style format, an unknown directive is assumed to have a single
@@ -20,13 +20,13 @@ example(uint64_t u64)
{
char buf[64];
- /* expect+4: warning: unknown directive 'x' [374] */
+ /* expect+4: warning: unknown directive 'x', must be one of 'bfF=:*' [374] */
snprintb(buf, sizeof(buf),
"\177\020"
"x12345\0",
u64);
- /* expect+4: warning: unknown directive '\000' [374] */
+ /* expect+4: warning: unknown directive '\000', must be one of 'bfF=:*' [374] */
snprintb(buf, sizeof(buf),
"\177\020"
"\00012345\0",
@@ -38,4 +38,15 @@ example(uint64_t u64)
"b\00012345\0"
"\0",
u64);
+
+ // Real-life example: the '\b' is a typo.
+ //
+ // TODO: Warn about the description that is split between string
+ // literals for no apparent reason.
+ //
+ /* expect+4: warning: unknown directive '\b', must be one of 'bfF=:*' [374] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "b\15ENCNT\0b\16" "TC\0\b\20DSBL_" "CSR_DRN\0",
+ u64);
}
Index: src/usr.bin/xlint/lint1/cksnprintb.c
diff -u src/usr.bin/xlint/lint1/cksnprintb.c:1.5 src/usr.bin/xlint/lint1/cksnprintb.c:1.6
--- src/usr.bin/xlint/lint1/cksnprintb.c:1.5 Sun Mar 3 10:27:18 2024
+++ src/usr.bin/xlint/lint1/cksnprintb.c Sun Mar 3 13:09:22 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: cksnprintb.c,v 1.5 2024/03/03 10:27:18 rillig Exp $ */
+/* $NetBSD: cksnprintb.c,v 1.6 2024/03/03 13:09:22 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.5 2024/03/03 10:27:18 rillig Exp $");
+__RCSID("$NetBSD: cksnprintb.c,v 1.6 2024/03/03 13:09:22 rillig Exp $");
#endif
#include <stdbool.h>
@@ -47,6 +47,8 @@ typedef struct {
bool new_style;
const buffer *fmt;
const tnode_t *value;
+
+ quoted_iterator it;
uint64_t field_width;
uint64_t covered;
unsigned covered_start[64];
@@ -141,7 +143,7 @@ check_overlap(checker *ck, uint64_t dir_
uint64_t field_mask = value_bits((unsigned)width) << lsb;
uint64_t overlap = ck->covered & field_mask;
if (overlap == 0)
- goto done;
+ goto update_covered;
for (unsigned i = lsb; i < 64; i++) {
if (!(overlap & bit(i)))
@@ -155,7 +157,7 @@ check_overlap(checker *ck, uint64_t dir_
break;
}
-done:
+update_covered:
ck->covered |= field_mask;
for (unsigned i = lsb; i < 64; i++) {
if (field_mask & bit(i)) {
@@ -174,39 +176,31 @@ check_reachable(checker *ck, uint64_t di
return;
uint64_t field_mask = value_bits((unsigned)width) << lsb;
- if (!(possible_bits(ck->value) & field_mask)) {
+ if (!(possible_bits(ck->value) & field_mask))
/* directive '%.*s' is unreachable by input value */
warning(378, (int)(end - start), ck->fmt->data + start);
- }
}
static void
-parse_description(const checker *ck, quoted_iterator *it,
- bool *seen_null, bool *descr_empty)
+parse_description(checker *ck, bool *seen_null, bool *descr_empty)
{
- bool new_style = ck->new_style;
-
- quoted_iterator first = *it;
+ quoted_iterator first = ck->it;
(void)quoted_next(ck->fmt, &first);
size_t descr_start = first.start, descr_end = descr_start;
- for (quoted_iterator peek = *it; quoted_next(ck->fmt, &peek);) {
- if (new_style && peek.value == 0) {
+ for (quoted_iterator peek = ck->it; quoted_next(ck->fmt, &peek);) {
+ if (!ck->new_style && peek.value <= 32)
+ break;
+ ck->it = peek;
+ if (ck->new_style && peek.value == 0) {
*seen_null = true;
- *it = peek;
break;
}
- if (!new_style && peek.value == 0)
- /* old-style format contains '\0' */
- warning(362);
- if (!new_style && peek.value <= 32)
- break;
- *it = peek;
descr_end = peek.i;
if (peek.escaped && !isprint((unsigned char)peek.value)) {
/* non-printing character '%.*s' in description ... */
warning(363,
- len(*it), start(*it, ck->fmt),
+ len(ck->it), start(ck->it, ck->fmt),
(int)(descr_end - descr_start),
ck->fmt->data + descr_start);
}
@@ -215,9 +209,11 @@ parse_description(const checker *ck, quo
}
static bool
-check_directive(const buffer *fmt, quoted_iterator *it, bool new_style,
- checker *ck)
+check_directive(checker *ck)
{
+ bool new_style = ck->new_style;
+ const buffer *fmt = ck->fmt;
+ quoted_iterator *it = &ck->it;
if (!quoted_next(fmt, it))
return false;
@@ -263,14 +259,17 @@ check_directive(const buffer *fmt, quote
}
if (!has_bit && !has_cmp && !has_default) {
- /* unknown directive '%.*s' */
+ /* unknown directive '%.*s', must be one of 'bfF=:*' */
warning(374, len(dir), start(dir, fmt));
return false;
}
+ if (new_style && dir.escaped)
+ /* directive '%.*s' should not be escaped */
+ warning(362, len(dir), start(dir, fmt));
bool needs_descr = !(new_style && dir.value == 'F');
bool seen_null = false, descr_empty = false;
- parse_description(ck, it, &seen_null, &descr_empty);
+ parse_description(ck, &seen_null, &descr_empty);
if (has_bit)
check_hex_escape(fmt, bit);
@@ -293,12 +292,11 @@ check_directive(const buffer *fmt, quote
range(dir, *it), start(dir, fmt),
new_style ? 0 : 1, new_style ? 63 : 32);
}
- if (has_width && width.value > (new_style ? 64 : 32)) {
- /* field width '%.*s' (%ju) in '%.*s' out of range 0..%u */
+ if (has_width && width.value > 64) {
+ /* field width '%.*s' (%ju) in '%.*s' out of range 0..64 */
warning(372,
len(width), start(width, fmt), val(width),
- range(dir, *it), start(dir, fmt),
- new_style ? 64 : 32);
+ range(dir, *it), start(dir, fmt));
}
if (has_width && bit.value + width.value > 64) {
/* bit field end %ju in '%.*s' out of range 0..64 */
@@ -314,19 +312,14 @@ check_directive(const buffer *fmt, quote
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 (needs_descr && descr_empty) {
+ if (needs_descr && descr_empty)
/* empty description in '%.*s' */
warning(367, range(dir, *it), start(dir, fmt));
- }
- if (new_style && !seen_null) {
+ if (new_style && !seen_null)
/* missing '\0' at the end of '%.*s' */
warning(366, range(dir, *it), start(dir, fmt));
- }
if (has_width)
ck->field_width = width.value;
@@ -341,30 +334,29 @@ check_snprintb(const tnode_t *expr)
if (!match_snprintb_call(expr->tn_call, &fmt, &value))
return;
- quoted_iterator it = { .i = 0 };
- if (!quoted_next(fmt, &it)) {
+ checker ck = {
+ .fmt = fmt,
+ .value = value,
+ .field_width = 64,
+ };
+
+ if (!quoted_next(fmt, &ck.it)) {
/* missing new-style '\177' or old-style number base */
warning(359);
return;
}
- bool new_style = it.value == '\177';
- if (new_style && !quoted_next(fmt, &it)) {
+ ck.new_style = ck.it.value == '\177';
+ if (ck.new_style && !quoted_next(fmt, &ck.it)) {
/* missing new-style number base after '\177' */
warning(360);
return;
}
- if (it.value != 8 && it.value != 10 && it.value != 16) {
+ if (ck.it.value != 8 && ck.it.value != 10 && ck.it.value != 16) {
/* number base '%.*s' is %ju, must be 8, 10 or 16 */
- warning(361, len(it), start(it, fmt), val(it));
+ warning(361, len(ck.it), start(ck.it, fmt), val(ck.it));
return;
}
- checker ck = {
- .new_style = new_style,
- .fmt = fmt,
- .value = value,
- .field_width = 64,
- };
- while (check_directive(fmt, &it, new_style, &ck))
+ while (check_directive(&ck))
continue;
}
Index: src/usr.bin/xlint/lint1/err.c
diff -u src/usr.bin/xlint/lint1/err.c:1.230 src/usr.bin/xlint/lint1/err.c:1.231
--- src/usr.bin/xlint/lint1/err.c:1.230 Sun Mar 3 10:27:18 2024
+++ src/usr.bin/xlint/lint1/err.c Sun Mar 3 13:09:22 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: err.c,v 1.230 2024/03/03 10:27:18 rillig Exp $ */
+/* $NetBSD: err.c,v 1.231 2024/03/03 13:09:22 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.230 2024/03/03 10:27:18 rillig Exp $");
+__RCSID("$NetBSD: err.c,v 1.231 2024/03/03 13:09:22 rillig Exp $");
#endif
#include <limits.h>
@@ -417,7 +417,7 @@ static const char *const msgs[] = {
"missing new-style '\\177' or old-style number base", // 359
"missing new-style number base after '\\177'", // 360
"number base '%.*s' is %ju, must be 8, 10 or 16", // 361
- "old-style format contains '\\0'", // 362
+ "directive '%.*s' should not be escaped", // 362
"non-printing character '%.*s' in description '%.*s'", // 363
"missing bit position after '%.*s'", // 364
"missing field width after '%.*s'", // 365
@@ -427,9 +427,9 @@ static const char *const msgs[] = {
"bit position '%.*s' in '%.*s' should be escaped as octal or hex", // 369
"field width '%.*s' in '%.*s' should be escaped as octal or hex", // 370
"bit position '%.*s' (%ju) in '%.*s' out of range %u..%u", // 371
- "field width '%.*s' (%ju) in '%.*s' out of range 0..%u", // 372
+ "field width '%.*s' (%ju) in '%.*s' out of range 0..64", // 372
"bit field end %ju in '%.*s' out of range 0..64", // 373
- "unknown directive '%.*s'", // 374
+ "unknown directive '%.*s', must be one of 'bfF=:*'", // 374
"comparison value '%.*s' (%ju) exceeds maximum field value %ju", // 375
"'%.*s' overlaps earlier '%.*s' on bit %u", // 376
"redundant '\\0' at the end of the format", // 377