Module Name: src Committed By: rillig Date: Wed Mar 13 06:48:49 UTC 2024
Modified Files: src/usr.bin/xlint/lint1: cksnprintb.c Log Message: lint: trim down the check for snprintb formats To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/usr.bin/xlint/lint1/cksnprintb.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/xlint/lint1/cksnprintb.c diff -u src/usr.bin/xlint/lint1/cksnprintb.c:1.10 src/usr.bin/xlint/lint1/cksnprintb.c:1.11 --- src/usr.bin/xlint/lint1/cksnprintb.c:1.10 Sun Mar 10 16:27:16 2024 +++ src/usr.bin/xlint/lint1/cksnprintb.c Wed Mar 13 06:48:49 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: cksnprintb.c,v 1.10 2024/03/10 16:27:16 rillig Exp $ */ +/* $NetBSD: cksnprintb.c,v 1.11 2024/03/13 06:48:49 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.10 2024/03/10 16:27:16 rillig Exp $"); +__RCSID("$NetBSD: cksnprintb.c,v 1.11 2024/03/13 06:48:49 rillig Exp $"); #endif #include <stdbool.h> @@ -51,35 +51,10 @@ typedef struct { quoted_iterator it; uint64_t field_width; uint64_t covered; - unsigned covered_start[64]; - unsigned covered_end[64]; + const char *covered_start[64]; + int covered_len[64]; } checker; -static bool -match_string_literal(const tnode_t *tn, const buffer **str) -{ - while (tn->tn_op == CVT) - tn = tn->u.ops.left; - return tn->tn_op == ADDR - && tn->u.ops.left->tn_op == STRING - && (*str = tn->u.ops.left->u.str_literals, (*str)->data != NULL); -} - -static bool -match_snprintb_call(const function_call *call, - const buffer **fmt, const tnode_t **val) -{ - const char *func; - - return call->func->tn_op == ADDR - && call->func->u.ops.left->tn_op == NAME - && (func = call->func->u.ops.left->u.sym->s_name, true) - && ((strcmp(func, "snprintb") == 0 && call->args_len == 4) - || (strcmp(func, "snprintb_m") == 0 && call->args_len == 5)) - && match_string_literal(call->args[2], fmt) - && (*val = call->args[3], true); -} - static int len(quoted_iterator it) { @@ -126,52 +101,36 @@ check_hex_escape(const buffer *buf, quot } static void -check_overlap(checker *ck, uint64_t dir_lsb, uint64_t width, - size_t start, size_t end) +check_bit(checker *ck, uint64_t dir_lsb, uint64_t width, + const char *start, int len) { 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; - if (overlap == 0) - goto update_covered; - for (unsigned i = lsb; i < 64; i++) { - if (!(overlap & bit(i))) - continue; - /* '%.*s' overlaps earlier '%.*s' on bit %u */ - warning(376, - (int)(end - start), ck->fmt->data + start, - (int)(ck->covered_end[i] - ck->covered_start[i]), - ck->fmt->data + ck->covered_start[i], - ck->new_style ? i : i + 1); - break; + if (ck->covered & field_mask & bit(i)) { + /* '%.*s' overlaps earlier '%.*s' on bit %u */ + warning(376, + len, start, ck->covered_len[i], + ck->covered_start[i], + ck->new_style ? i : i + 1); + break; + } } -update_covered: ck->covered |= field_mask; for (unsigned i = lsb; i < 64; i++) { if (field_mask & bit(i)) { - ck->covered_start[i] = (unsigned)start; - ck->covered_end[i] = (unsigned)end; + ck->covered_start[i] = start; + ck->covered_len[i] = len; } } -} - -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); + warning(378, len, start); } static bool @@ -266,45 +225,37 @@ check_directive(checker *ck) check_hex_escape(fmt, bit); if (has_width) check_hex_escape(fmt, width); - if (has_bit && bit.octal_digits == 0 && bit.hex_digits == 0) { + if (has_bit && bit.octal_digits == 0 && bit.hex_digits == 0) /* bit position '%.*s' in '%.*s' should be escaped as ... */ warning(369, len(bit), start(bit, fmt), range(dir, *it), start(dir, fmt)); - } - if (has_width && width.octal_digits == 0 && width.hex_digits == 0) { + if (has_width && width.octal_digits == 0 && width.hex_digits == 0) /* field width '%.*s' in '%.*s' should be escaped as ... */ warning(370, len(width), start(width, fmt), range(dir, *it), start(dir, fmt)); - } - if (has_bit && (new_style ? bit.value > 63 : bit.value - 1 > 31)) { + if (has_bit && (new_style ? bit.value > 63 : bit.value - 1 > 31)) /* bit position '%.*s' (%ju) in '%.*s' out of range %u..%u */ warning(371, len(bit), start(bit, fmt), val(bit), range(dir, *it), start(dir, fmt), new_style ? 0 : 1, new_style ? 63 : 32); - } - if (has_width && width.value > 64) { + 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)); - } - if (has_width && bit.value + width.value > 64) { + if (has_width && bit.value + width.value > 64) /* bit field end %ju in '%.*s' out of range 0..64 */ warning(373, val(bit) + val(width), range(dir, *it), start(dir, fmt)); - } if (has_cmp && ck->field_width > 0 && ck->field_width < 64 - && cmp.value & ~value_bits((unsigned)ck->field_width)) { + && cmp.value & ~value_bits((unsigned)ck->field_width)) /* comparison value '%.*s' (%ju) exceeds maximum field ... */ warning(375, len(cmp), start(cmp, fmt), val(cmp), (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->end); - check_reachable(ck, bit.value, w, dir.start, it->end); - } + if (has_bit) + check_bit(ck, bit.value, has_width ? width.value : 1, + ck->fmt->data + dir.start, (int)(it->end - dir.start)); if (needs_descr && !seen_descr) /* empty description in '%.*s' */ warning(367, range(dir, *it), start(dir, fmt)); @@ -320,9 +271,22 @@ check_directive(checker *ck) void check_snprintb(const tnode_t *expr) { + const function_call *call = expr->u.call; + const char *name; const buffer *fmt; const tnode_t *value; - if (!match_snprintb_call(expr->u.call, &fmt, &value)) + + if (!(call->func->tn_op == ADDR + && call->func->u.ops.left->tn_op == NAME + && (name = call->func->u.ops.left->u.sym->s_name, true) + && ((strcmp(name, "snprintb") == 0 && call->args_len == 4) + || (strcmp(name, "snprintb_m") == 0 && call->args_len == 5)) + && call->args[2]->tn_op == CVT + && call->args[2]->u.ops.left->tn_op == ADDR + && call->args[2]->u.ops.left->u.ops.left->tn_op == STRING + && (fmt = call->args[2]->u.ops.left->u.ops.left->u.str_literals, + fmt->data != NULL) + && (value = call->args[3], true))) return; checker ck = {