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