Module Name: src Committed By: rillig Date: Wed Sep 13 20:31:58 UTC 2023
Modified Files: src/usr.bin/xlint/common: lint.h src/usr.bin/xlint/lint1: ckctype.c debug.c emit1.c lint1.h op.h oper.c ops.def tree.c Log Message: lint: prevent invalid memory access when checking an expression In check_expr_misc, the left and right operands of an expression were accessed even in the case of CON (constant), STRING (string literal) and NAME (identifier), which led to invalid values in pointer variables. These invalid values were not used though, but technically they invoked undefined behavior. Precede each access to the operands with a check that the expression indeed has operands, except in those cases where the operand is known to have operands by only looking at the code of the current function. To generate a diff of this commit: cvs rdiff -u -r1.43 -r1.44 src/usr.bin/xlint/common/lint.h cvs rdiff -u -r1.6 -r1.7 src/usr.bin/xlint/lint1/ckctype.c cvs rdiff -u -r1.61 -r1.62 src/usr.bin/xlint/lint1/debug.c cvs rdiff -u -r1.76 -r1.77 src/usr.bin/xlint/lint1/emit1.c cvs rdiff -u -r1.200 -r1.201 src/usr.bin/xlint/lint1/lint1.h cvs rdiff -u -r1.21 -r1.22 src/usr.bin/xlint/lint1/op.h cvs rdiff -u -r1.11 -r1.12 src/usr.bin/xlint/lint1/oper.c cvs rdiff -u -r1.30 -r1.31 src/usr.bin/xlint/lint1/ops.def cvs rdiff -u -r1.580 -r1.581 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/usr.bin/xlint/common/lint.h diff -u src/usr.bin/xlint/common/lint.h:1.43 src/usr.bin/xlint/common/lint.h:1.44 --- src/usr.bin/xlint/common/lint.h:1.43 Sat Aug 12 18:05:51 2023 +++ src/usr.bin/xlint/common/lint.h Wed Sep 13 20:31:58 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: lint.h,v 1.43 2023/08/12 18:05:51 rillig Exp $ */ +/* $NetBSD: lint.h,v 1.44 2023/09/13 20:31:58 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -134,6 +134,8 @@ type_properties(tspec_t t) { #define is_complex(t) (type_properties(t)->tt_is_complex) #define is_scalar(t) (type_properties(t)->tt_is_scalar) +#define has_operands(tn) (modtab[(tn)->tn_op].m_has_operands) + typedef enum { NODECL, /* not declared until now */ Index: src/usr.bin/xlint/lint1/ckctype.c diff -u src/usr.bin/xlint/lint1/ckctype.c:1.6 src/usr.bin/xlint/lint1/ckctype.c:1.7 --- src/usr.bin/xlint/lint1/ckctype.c:1.6 Wed Aug 2 18:51:25 2023 +++ src/usr.bin/xlint/lint1/ckctype.c Wed Sep 13 20:31:58 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: ckctype.c,v 1.6 2023/08/02 18:51:25 rillig Exp $ */ +/* $NetBSD: ckctype.c,v 1.7 2023/09/13 20:31:58 rillig Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) -__RCSID("$NetBSD: ckctype.c,v 1.6 2023/08/02 18:51:25 rillig Exp $"); +__RCSID("$NetBSD: ckctype.c,v 1.7 2023/09/13 20:31:58 rillig Exp $"); #endif #include <string.h> @@ -126,7 +126,7 @@ check_ctype_function_call(const tnode_t if (func->tn_op == NAME && is_ctype_function(func->tn_sym->s_name) && args != NULL && - args->tn_left != NULL && + tn_ck_left(args) != NULL && args->tn_right == NULL) check_ctype_arg(func->tn_sym->s_name, args->tn_left); } Index: src/usr.bin/xlint/lint1/debug.c diff -u src/usr.bin/xlint/lint1/debug.c:1.61 src/usr.bin/xlint/lint1/debug.c:1.62 --- src/usr.bin/xlint/lint1/debug.c:1.61 Wed Aug 2 21:58:11 2023 +++ src/usr.bin/xlint/lint1/debug.c Wed Sep 13 20:31:58 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: debug.c,v 1.61 2023/08/02 21:58:11 rillig Exp $ */ +/* $NetBSD: debug.c,v 1.62 2023/09/13 20:31:58 rillig Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) -__RCSID("$NetBSD: debug.c,v 1.61 2023/08/02 21:58:11 rillig Exp $"); +__RCSID("$NetBSD: debug.c,v 1.62 2023/09/13 20:31:58 rillig Exp $"); #endif #include <stdlib.h> @@ -253,6 +253,7 @@ debug_node(const tnode_t *tn) // NOLINT( debug_printf("\n"); debug_indent_inc(); + lint_assert(has_operands(tn)); lint_assert(tn->tn_left != NULL); debug_node(tn->tn_left); if (op != INCBEF && op != INCAFT Index: src/usr.bin/xlint/lint1/emit1.c diff -u src/usr.bin/xlint/lint1/emit1.c:1.76 src/usr.bin/xlint/lint1/emit1.c:1.77 --- src/usr.bin/xlint/lint1/emit1.c:1.76 Sat Aug 12 21:32:16 2023 +++ src/usr.bin/xlint/lint1/emit1.c Wed Sep 13 20:31:58 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: emit1.c,v 1.76 2023/08/12 21:32:16 rillig Exp $ */ +/* $NetBSD: emit1.c,v 1.77 2023/09/13 20:31:58 rillig Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. @@ -38,7 +38,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) -__RCSID("$NetBSD: emit1.c,v 1.76 2023/08/12 21:32:16 rillig Exp $"); +__RCSID("$NetBSD: emit1.c,v 1.77 2023/09/13 20:31:58 rillig Exp $"); #endif #include "lint1.h" @@ -338,8 +338,8 @@ outcall(const tnode_t *tn, bool retval_u * the function */ narg = 0; - args = tn->tn_right; - for (arg = args; arg != NULL; arg = arg->tn_right) + args = tn_ck_right(tn); + for (arg = args; arg != NULL; arg = tn_ck_right(arg)) narg++; /* information about arguments */ for (n = 1; n <= narg; n++) { @@ -379,7 +379,7 @@ outcall(const tnode_t *tn, bool retval_u outchar((char)(retval_discarded ? 'd' : retval_used ? 'u' : 'i')); /* name of the called function */ - outname(tn->tn_left->tn_left->tn_sym->s_name); + outname(tn_ck_left(tn->tn_left)->tn_sym->s_name); /* types of arguments */ outchar('f'); Index: src/usr.bin/xlint/lint1/lint1.h diff -u src/usr.bin/xlint/lint1/lint1.h:1.200 src/usr.bin/xlint/lint1/lint1.h:1.201 --- src/usr.bin/xlint/lint1/lint1.h:1.200 Sat Aug 26 10:43:53 2023 +++ src/usr.bin/xlint/lint1/lint1.h Wed Sep 13 20:31:58 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: lint1.h,v 1.200 2023/08/26 10:43:53 rillig Exp $ */ +/* $NetBSD: lint1.h,v 1.201 2023/09/13 20:31:58 rillig Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. @@ -502,6 +502,20 @@ typedef enum { assert_failed(__FILE__, __LINE__, __func__, #cond); \ } while (false) +static inline tnode_t * +tn_ck_left(const tnode_t *tn) +{ + lint_assert(has_operands(tn)); + return tn->tn_left; +} + +static inline tnode_t * +tn_ck_right(const tnode_t *tn) +{ + lint_assert(has_operands(tn)); + return tn->tn_right; +} + #ifdef DEBUG # include "err-msgs.h" Index: src/usr.bin/xlint/lint1/op.h diff -u src/usr.bin/xlint/lint1/op.h:1.21 src/usr.bin/xlint/lint1/op.h:1.22 --- src/usr.bin/xlint/lint1/op.h:1.21 Thu Jul 13 08:40:38 2023 +++ src/usr.bin/xlint/lint1/op.h Wed Sep 13 20:31:58 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: op.h,v 1.21 2023/07/13 08:40:38 rillig Exp $ */ +/* $NetBSD: op.h,v 1.22 2023/09/13 20:31:58 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -56,6 +56,7 @@ typedef struct { bool m_valid_on_enum: 1; bool m_bad_on_enum: 1; bool m_warn_if_operand_eq: 1; + bool m_has_operands: 1; const char *m_name; } mod_t; @@ -68,7 +69,8 @@ extern const mod_t modtab[]; can_fold, is_value, unused, balances_operands, \ side_effects, left_unsigned, right_unsigned, \ precedence_confusion, is_comparison, \ - valid_on_enum, bad_on_enum, warn_if_eq) \ + valid_on_enum, bad_on_enum, warn_if_eq, \ + has_operands) \ name, #define end_ops() } op_t; #include "ops.def" Index: src/usr.bin/xlint/lint1/oper.c diff -u src/usr.bin/xlint/lint1/oper.c:1.11 src/usr.bin/xlint/lint1/oper.c:1.12 --- src/usr.bin/xlint/lint1/oper.c:1.11 Sat Apr 16 22:21:10 2022 +++ src/usr.bin/xlint/lint1/oper.c Wed Sep 13 20:31:58 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: oper.c,v 1.11 2022/04/16 22:21:10 rillig Exp $ */ +/* $NetBSD: oper.c,v 1.12 2023/09/13 20:31:58 rillig Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -41,7 +41,7 @@ const mod_t modtab[NOPS] = can_fold, is_value, unused, balances_operands, \ side_effects, left_unsigned, right_unsigned, \ precedence_confusion, is_comparison, \ - valid_on_enum, bad_on_enum, warn_if_eq) \ + valid_on_enum, bad_on_enum, warn_if_eq, has_operands) \ { \ is_binary + 0 > 0, is_logical + 0 > 0, \ takes_bool + 0 > 0, requires_bool + 0 > 0, \ @@ -53,6 +53,7 @@ const mod_t modtab[NOPS] = right_unsigned + 0 > 0, precedence_confusion + 0 > 0, \ is_comparison + 0 > 0, valid_on_enum + 0 > 0, \ bad_on_enum + 0 > 0, warn_if_eq + 0 > 0, \ + has_operands + 0 > 0, \ repr, \ }, #define end_ops(n) }; Index: src/usr.bin/xlint/lint1/ops.def diff -u src/usr.bin/xlint/lint1/ops.def:1.30 src/usr.bin/xlint/lint1/ops.def:1.31 --- src/usr.bin/xlint/lint1/ops.def:1.30 Sat Jun 3 20:58:00 2023 +++ src/usr.bin/xlint/lint1/ops.def Wed Sep 13 20:31:58 2023 @@ -1,123 +1,124 @@ -/* $NetBSD: ops.def,v 1.30 2023/06/03 20:58:00 rillig Exp $ */ +/* $NetBSD: ops.def,v 1.31 2023/09/13 20:31:58 rillig Exp $ */ begin_ops() /* * Operator properties; see mod_t in op.h. * - * warn if operand '=' x - * bad on enum x - * valid on enum x - * comparison - - - - - - - - - - - - - - - - x - * possible precedence confusion x | - * warn if right operand unsigned x | - * warn if left operand unsigned x | - * has side effects - - - - - - - - - - - - x | - * balance operands x | | - * (unused) x | | - * value context x | | - * fold constant operands - - - - - - - - x | | - * requires scalar x | | | - * requires arithmetic x | | | - * requires integer or complex x | | | - * requires integer - - - - x | | | - * compares with zero x | | | | - * takes _Bool x | | | | - * logical x | | | | - * binary x | | | | + * has operands - - - - - - - - - - - - - - - - - - - - x + * warn if operand '=' x | + * bad on enum x | + * valid on enum x | + * comparison - - - - - - - - - - - - - - - - x | + * possible precedence confusion x | | + * warn if right operand unsigned x | | + * warn if left operand unsigned x | | + * has side effects - - - - - - - - - - - - x | | + * balance operands x | | | + * (unused) x | | | + * value context x | | | + * fold constant operands - - - - - - - - x | | | + * requires scalar x | | | | + * requires arithmetic x | | | | + * requires integer or complex x | | | | + * requires integer - - - - x | | | | + * compares with zero x | | | | | + * takes _Bool x | | | | | + * logical x | | | | | + * binary x | | | | | */ -/* name repr b l b z i c a s f v - b s l r p c e e = */ -op( NOOP, "no-op", , , , , , , , , , , , , , , , , , , , ) -op( ARROW, "->", 1, ,1, , , , , , ,1, , , , , , , , , , ) -op( POINT, ".", 1, ,1, , , , , , , , , , , , , , , , , ) -op( NOT, "!", ,1,1,1, , , ,1,1, , , , , , , , , ,1, ) -op( COMPL, "~", , , , , ,1, , ,1,1, , , , , , , , ,1,1) -op( INC, "++", , , , , , , , , , , , , , , , , , , , ) -op( DEC, "--", , , , , , , , , , , , , , , , , , , , ) +/* name repr b l b z i c a s f v - b s l r p c e e = o */ +op( NOOP, "no-op", , , , , , , , , , , , , , , , , , , , , ) +op( ARROW, "->", 1, ,1, , , , , , ,1, , , , , , , , , , ,1) +op( POINT, ".", 1, ,1, , , , , , , , , , , , , , , , , ,1) +op( NOT, "!", ,1,1,1, , , ,1,1, , , , , , , , , ,1, ,1) +op( COMPL, "~", , , , , ,1, , ,1,1, , , , , , , , ,1,1,1) +op( INC, "++", , , , , , , , , , , , , , , , , , , , ,1) +op( DEC, "--", , , , , , , , , , , , , , , , , , , , ,1) /* * The '++' and '--' operators are conceptually unary operators, but lint * implements them as binary operators due to the pre-multiplied pointer * arithmetics, see build_prepost_incdec and build_plus_minus. */ -op( INCBEF, "++x", , , , , , , ,1, , , , ,1, , , , , ,1, ) -op( DECBEF, "--x", , , , , , , ,1, , , , ,1, , , , , ,1, ) -op( INCAFT, "x++", , , , , , , ,1, , , , ,1, , , , , ,1, ) -op( DECAFT, "x--", , , , , , , ,1, , , , ,1, , , , , ,1, ) -op( UPLUS, "+", , , , , , ,1, ,1,1, , , , , , , , ,1,1) -op( UMINUS, "-", , , , , , ,1, ,1,1, , , ,1, , , , ,1,1) -op( INDIR, "*", , , , , , , , , ,1, , , , , , , , , , ) -op( ADDR, "&", , ,1, , , , , , , , , , , , , , , , , ) +op( INCBEF, "++x", , , , , , , ,1, , , , ,1, , , , , ,1, ,1) +op( DECBEF, "--x", , , , , , , ,1, , , , ,1, , , , , ,1, ,1) +op( INCAFT, "x++", , , , , , , ,1, , , , ,1, , , , , ,1, ,1) +op( DECAFT, "x--", , , , , , , ,1, , , , ,1, , , , , ,1, ,1) +op( UPLUS, "+", , , , , , ,1, ,1,1, , , , , , , , ,1,1,1) +op( UMINUS, "-", , , , , , ,1, ,1,1, , , ,1, , , , ,1,1,1) +op( INDIR, "*", , , , , , , , , ,1, , , , , , , , , , ,1) +op( ADDR, "&", , ,1, , , , , , , , , , , , , , , , , ,1) /* the operator 'arr[ind]' is translated to '*(arr + ind)' during parsing. */ -/* name repr b l b z i c a s f v - b s l r p c e e = */ -op( MULT, "*", 1, , , , , ,1, ,1,1, ,1, , ,1, , , ,1,1) -op( DIV, "/", 1, , , , , ,1, ,1,1, ,1, ,1,1, , , ,1,1) -op( MOD, "%", 1, , , ,1, , , ,1,1, ,1, ,1,1, , , ,1,1) -op( PLUS, "+", 1, , , , , , ,1,1,1, ,1, , , , , , ,1, ) -op( MINUS, "-", 1, , , , , , ,1,1,1, ,1, , , , , , ,1, ) -op( SHL, "<<", 1, , , ,1, , , ,1,1, , , , , ,1, , ,1,1) -op( SHR, ">>", 1, , , ,1, , , ,1,1, , , ,1, ,1, , ,1,1) - -/* name repr b l b z i c a s f v - b s l r p c e e = */ -op( LT, "<", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1) -op( LE, "<=", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1) -op( GT, ">", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1) -op( GE, ">=", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1) -op( EQ, "==", 1,1,1, , , , ,1,1,1, ,1, , , , ,1,1, ,1) -op( NE, "!=", 1,1,1, , , , ,1,1,1, ,1, , , , ,1,1, ,1) - -/* name repr b l b z i c a s f v - b s l r p c e e = */ -op( BITAND, "&", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ) -op( BITXOR, "^", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ) -op( BITOR, "|", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ) -op( LOGAND, "&&", 1,1,1,1, , , ,1,1, , , , , , , , , ,1, ) -op( LOGOR, "||", 1,1,1,1, , , ,1,1, , , , , , ,1, , ,1, ) -op( QUEST, "?", 1, , ,1, , , , ,1, , , , , , , , , , , ) -op( COLON, ":", 1, ,1, , , , , , ,1, ,1, , , , , ,1, , ) - -/* name repr b l b z i c a s f v - b s l r p c e e = */ -op( ASSIGN, "=", 1, ,1, , , , , , , , , ,1, , , , ,1, , ) -op( MULASS, "*=", 1, , , , , ,1, , , , , ,1, , , , , ,1, ) -op( DIVASS, "/=", 1, , , , , ,1, , , , , ,1, ,1, , , ,1, ) -op( MODASS, "%=", 1, , , ,1, , , , , , , ,1, ,1, , , ,1, ) -op( ADDASS, "+=", 1, , , , , , ,1, , , , ,1, , , , , ,1, ) -op( SUBASS, "-=", 1, , , , , , ,1, , , , ,1, , , , , ,1, ) -op( SHLASS, "<<=", 1, , , ,1, , , , , , , ,1, , , , , ,1, ) -op( SHRASS, ">>=", 1, , , ,1, , , , , , , ,1, , , , , ,1, ) -op( ANDASS, "&=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ) -op( XORASS, "^=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ) -op( ORASS, "|=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ) - -/* name repr b l b z i c a s f v - b s l r p c e e = */ -op( NAME, "name", , , , , , , , , , , , , , , , , , , , ) -op( CON, "constant", , , , , , , , , , , , , , , , , , , , ) -op( STRING, "string", , , , , , , , , , , , , , , , , , , , ) -op( FSEL, "fsel", , , , , , , , , , , , , , , , , , , , ) -op( CALL, "call", 1, , , , , , , , , , , ,1, , , , , , , ) -op( COMMA, ",", 1, ,1, , , , , , , , , , , , , , , , ,1) -op( CVT, "convert", , , , , , , , , ,1, , , , , , , , , , ) -op( ICALL, "icall", 1, , , , , , , , , , , ,1, , , , , , , ) -op( LOAD, "load", , , , , , , , , , , , , , , , , , , , ) +/* name repr b l b z i c a s f v - b s l r p c e e = o */ +op( MULT, "*", 1, , , , , ,1, ,1,1, ,1, , ,1, , , ,1,1,1) +op( DIV, "/", 1, , , , , ,1, ,1,1, ,1, ,1,1, , , ,1,1,1) +op( MOD, "%", 1, , , ,1, , , ,1,1, ,1, ,1,1, , , ,1,1,1) +op( PLUS, "+", 1, , , , , , ,1,1,1, ,1, , , , , , ,1, ,1) +op( MINUS, "-", 1, , , , , , ,1,1,1, ,1, , , , , , ,1, ,1) +op( SHL, "<<", 1, , , ,1, , , ,1,1, , , , , ,1, , ,1,1,1) +op( SHR, ">>", 1, , , ,1, , , ,1,1, , , ,1, ,1, , ,1,1,1) + +/* name repr b l b z i c a s f v - b s l r p c e e = o */ +op( LT, "<", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1,1) +op( LE, "<=", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1,1) +op( GT, ">", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1,1) +op( GE, ">=", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1,1) +op( EQ, "==", 1,1,1, , , , ,1,1,1, ,1, , , , ,1,1, ,1,1) +op( NE, "!=", 1,1,1, , , , ,1,1,1, ,1, , , , ,1,1, ,1,1) + +/* name repr b l b z i c a s f v - b s l r p c e e = o */ +op( BITAND, "&", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ,1) +op( BITXOR, "^", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ,1) +op( BITOR, "|", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ,1) +op( LOGAND, "&&", 1,1,1,1, , , ,1,1, , , , , , , , , ,1, ,1) +op( LOGOR, "||", 1,1,1,1, , , ,1,1, , , , , , ,1, , ,1, ,1) +op( QUEST, "?", 1, , ,1, , , , ,1, , , , , , , , , , , ,1) +op( COLON, ":", 1, ,1, , , , , , ,1, ,1, , , , , ,1, , ,1) + +/* name repr b l b z i c a s f v - b s l r p c e e = o */ +op( ASSIGN, "=", 1, ,1, , , , , , , , , ,1, , , , ,1, , ,1) +op( MULASS, "*=", 1, , , , , ,1, , , , , ,1, , , , , ,1, ,1) +op( DIVASS, "/=", 1, , , , , ,1, , , , , ,1, ,1, , , ,1, ,1) +op( MODASS, "%=", 1, , , ,1, , , , , , , ,1, ,1, , , ,1, ,1) +op( ADDASS, "+=", 1, , , , , , ,1, , , , ,1, , , , , ,1, ,1) +op( SUBASS, "-=", 1, , , , , , ,1, , , , ,1, , , , , ,1, ,1) +op( SHLASS, "<<=", 1, , , ,1, , , , , , , ,1, , , , , ,1, ,1) +op( SHRASS, ">>=", 1, , , ,1, , , , , , , ,1, , , , , ,1, ,1) +op( ANDASS, "&=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ,1) +op( XORASS, "^=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ,1) +op( ORASS, "|=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ,1) + +/* name repr b l b z i c a s f v - b s l r p c e e = o */ +op( NAME, "name", , , , , , , , , , , , , , , , , , , , , ) +op( CON, "constant", , , , , , , , , , , , , , , , , , , , , ) +op( STRING, "string", , , , , , , , , , , , , , , , , , , , , ) +op( FSEL, "fsel", , , , , , , , , , , , , , , , , , , , ,1) +op( CALL, "call", 1, , , , , , , , , , , ,1, , , , , , , ,1) +op( COMMA, ",", 1, ,1, , , , , , , , , , , , , , , , ,1,1) +op( CVT, "convert", , , , , , , , , ,1, , , , , , , , , , ,1) +op( ICALL, "icall", 1, , , , , , , , , , , ,1, , , , , , , ,1) +op( LOAD, "load", , , , , , , , , , , , , , , , , , , , ,1) /* * PUSH is a virtual node that is used to concatenate arguments in a function * call expression. The PUSH nodes are ordered from right to left. For * example, the function call f(17, 23) is represented as * CALL(f, PUSH(23, PUSH(17, NULL))). */ -op( PUSH, "push", , , , , , , , , ,1, , , , , , , , , , ) -op( RETURN, "return", 1, ,1, , , , , , , , , ,1, , , , ,1, , ) -op( REAL, "real", , , , , , , , , , , , , , , , , , , , ) -op( IMAG, "imag", , , , , , , , , , , , , , , , , , , , ) +op( PUSH, "push", , , , , , , , , ,1, , , , , , , , , , ,1) +op( RETURN, "return", 1, ,1, , , , , , , , , ,1, , , , ,1, , ,1) +op( REAL, "real", , , , , , , , , , , , , , , , , , , , ,1) +op( IMAG, "imag", , , , , , , , , , , , , , , , , , , , ,1) /* INIT, CASE and FARG are pseudo operators that don't appear in the tree. */ -/* name repr b l b z i c a s f v - b s l r p c e e = */ -op( INIT, "init", 1, ,1, , , , , , , , , ,1, , , , ,1, , ) -op( CASE, "case", , , , , , , , , , , , , , , , , , , , ) +/* name repr b l b z i c a s f v - b s l r p c e e = o */ +op( INIT, "init", 1, ,1, , , , , , , , , ,1, , , , ,1, , ,1) +op( CASE, "case", , , , , , , , , , , , , , , , , , , , , ) /* * FARG is only used temporarily in check_prototype_argument to check type * compatibility and conversion for function arguments. */ -op( FARG, "farg", 1, ,1, , , , , , , , , , , , , , ,1, , ) +op( FARG, "farg", 1, ,1, , , , , , , , , , , , , , ,1, , ,1) end_ops() Index: src/usr.bin/xlint/lint1/tree.c diff -u src/usr.bin/xlint/lint1/tree.c:1.580 src/usr.bin/xlint/lint1/tree.c:1.581 --- src/usr.bin/xlint/lint1/tree.c:1.580 Tue Sep 12 22:01:05 2023 +++ src/usr.bin/xlint/lint1/tree.c Wed Sep 13 20:31:58 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: tree.c,v 1.580 2023/09/12 22:01:05 rillig Exp $ */ +/* $NetBSD: tree.c,v 1.581 2023/09/13 20:31:58 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.580 2023/09/12 22:01:05 rillig Exp $"); +__RCSID("$NetBSD: tree.c,v 1.581 2023/09/13 20:31:58 rillig Exp $"); #endif #include <float.h> @@ -794,6 +794,7 @@ fold(tnode_t *tn) val_t *v = xcalloc(1, sizeof(*v)); v->v_tspec = tn->tn_type->t_tspec; + lint_assert(has_operands(tn)); tspec_t t = tn->tn_left->tn_type->t_tspec; bool utyp = !is_integer(t) || is_uinteger(t); int64_t sl = tn->tn_left->tn_val.u.integer, sr = 0; @@ -1250,7 +1251,7 @@ build_colon(bool sys, tnode_t *ln, tnode static bool is_cast_redundant(const tnode_t *tn) { - const type_t *ntp = tn->tn_type, *otp = tn->tn_left->tn_type; + const type_t *ntp = tn->tn_type, *otp = tn_ck_left(tn)->tn_type; tspec_t nt = ntp->t_tspec, ot = otp->t_tspec; if (nt == BOOL || ot == BOOL) @@ -1485,6 +1486,7 @@ fold_bool(tnode_t *tn) v->v_tspec = tn->tn_type->t_tspec; lint_assert(v->v_tspec == INT || (Tflag && v->v_tspec == BOOL)); + lint_assert(has_operands(tn)); bool l = constant_is_nonzero(tn->tn_left); bool r = is_binary(tn) && constant_is_nonzero(tn->tn_right); @@ -1564,6 +1566,7 @@ fold_float(tnode_t *tn) v->v_tspec = t; lint_assert(is_floating(t)); + lint_assert(has_operands(tn)); lint_assert(t == tn->tn_left->tn_type->t_tspec); lint_assert(!is_binary(tn) || t == tn->tn_right->tn_type->t_tspec); @@ -1648,6 +1651,7 @@ use(const tnode_t *tn) case STRING: break; default: + lint_assert(has_operands(tn)); use(tn->tn_left); if (is_binary(tn) || tn->tn_op == PUSH) use(tn->tn_right); @@ -1828,6 +1832,7 @@ build_binary(tnode_t *ln, op_t op, bool ntn = fold(ntn); } } else if (op == QUEST && ln->tn_op == CON) { + lint_assert(has_operands(rn)); use(ln->tn_val.u.integer != 0 ? rn->tn_right : rn->tn_left); ntn = ln->tn_val.u.integer != 0 @@ -2702,11 +2707,12 @@ is_const_char_pointer(const tnode_t *tn) static bool is_first_arg_const_char_pointer(const tnode_t *tn) { + lint_assert(has_operands(tn)); const tnode_t *an = tn->tn_right; if (an == NULL) return false; - while (an->tn_right != NULL) + while (tn_ck_right(an) != NULL) an = an->tn_right; return is_const_char_pointer(an->tn_left); } @@ -2721,11 +2727,11 @@ is_const_pointer(const tnode_t *tn) static bool is_second_arg_const_pointer(const tnode_t *tn) { - const tnode_t *an = tn->tn_right; - if (an == NULL || an->tn_right == NULL) + const tnode_t *an = tn_ck_right(tn); + if (an == NULL || tn_ck_right(an) == NULL) return false; - while (an->tn_right->tn_right != NULL) + while (tn_ck_right(an->tn_right) != NULL) an = an->tn_right; return is_const_pointer(an->tn_left); } @@ -4260,7 +4266,7 @@ check_function_arguments(type_t *ftp, tn /* get # of arguments in the function call */ int narg = 0; - for (const tnode_t *arg = args; arg != NULL; arg = arg->tn_right) + for (const tnode_t *arg = args; arg != NULL; arg = tn_ck_right(arg)) narg++; const sym_t *param = ftp->t_params; @@ -4462,6 +4468,7 @@ expr(tnode_t *tn, bool vctx, bool cond, static void check_array_index(tnode_t *tn, bool amper) { + lint_assert(has_operands(tn)); const tnode_t *ln = tn->tn_left; const tnode_t *rn = tn->tn_right; @@ -4582,7 +4589,7 @@ check_expr_call(const tnode_t *tn, const outcall(tn, vctx || cond, retval_discarded); } -static bool +static void check_expr_op(const tnode_t *tn, op_t op, const tnode_t *ln, bool szof, bool fcall, bool vctx, bool cond, bool retval_discarded, bool eqwarn) @@ -4624,14 +4631,9 @@ check_expr_op(const tnode_t *tn, op_t op /* operator '==' found where '=' was expected */ warning(160); break; - case CON: - case NAME: - case STRING: - return false; default: break; } - return true; } /* @@ -4655,16 +4657,17 @@ check_expr_misc(const tnode_t *tn, bool if (tn == NULL) return; + op_t op = tn->tn_op; + if (op == NAME || op == CON || op == STRING) + return; + lint_assert(has_operands(tn)); tnode_t *ln = tn->tn_left; tnode_t *rn = tn->tn_right; - op_t op = tn->tn_op; - const mod_t *mp = &modtab[op]; - - if (!check_expr_op(tn, op, ln, - szof, fcall, vctx, cond, retval_discarded, eqwarn)) - return; + check_expr_op(tn, op, ln, + szof, fcall, vctx, cond, retval_discarded, eqwarn); + const mod_t *mp = &modtab[op]; bool cvctx = mp->m_value_context; bool ccond = mp->m_compares_with_zero; bool eq = mp->m_warn_if_operand_eq &&