unsigned_lt_zero: re-write this check
[smatch.git] / check_unsigned_lt_zero.c
blobbf8491906eec49f7b97c6be702508f4999fc126d
1 /*
2 * Copyright (C) 2009 Dan Carpenter.
3 * Copyright 2023 Linaro Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 #include "smatch.h"
20 #include "smatch_extra.h"
22 static int my_id;
24 static bool flip_order(struct expression *expr, struct expression **left, int *op, struct expression **right)
26 /* flip everything to < */
28 expr = strip_expr(expr);
30 switch (expr->op) {
31 case '>':
32 case SPECIAL_GTE:
33 case SPECIAL_UNSIGNED_GT:
34 case SPECIAL_UNSIGNED_GTE:
35 *left = strip_parens(expr->right);
36 *op = flip_comparison(expr->op);
37 *right = strip_parens(expr->left);
38 return true;
39 case '<':
40 case SPECIAL_LTE:
41 case SPECIAL_UNSIGNED_LT:
42 case SPECIAL_UNSIGNED_LTE:
43 *left = strip_parens(expr->left);
44 *op = expr->op;
45 *right = strip_parens(expr->right);
46 return true;
49 return false;
52 static bool is_upper(struct expression *var, struct expression *cond)
54 struct expression *left, *right;
55 int op;
57 cond = strip_expr(cond);
59 if (!flip_order(cond, &left, &op, &right))
60 return false;
61 if (expr_equiv(var, right))
62 return true;
63 return false;
66 static bool is_if_else_clamp_stmt(struct expression *var, struct expression *expr)
68 struct statement *stmt, *else_cond;
70 stmt = expr_get_parent_stmt(expr);
71 if (!stmt || stmt->type != STMT_IF)
72 return false;
73 if (is_upper(var, stmt->if_conditional))
74 return true;
76 else_cond = stmt->if_false;
77 if (!else_cond || else_cond->type != STMT_IF)
78 return false;
79 if (is_upper(var, else_cond->if_conditional))
80 return true;
82 return false;
85 static bool has_upper_bound(struct expression *var, struct expression *expr)
87 struct expression *parent, *prev;
89 parent = expr;
90 prev = expr;
91 while ((parent = expr_get_parent_expr(parent))) {
92 if (parent->type == EXPR_LOGICAL &&
93 parent->op == SPECIAL_LOGICAL_AND)
94 break;
95 if (parent->type == EXPR_LOGICAL &&
96 parent->op == SPECIAL_LOGICAL_OR) {
97 if (prev == parent->left &&
98 is_upper(var, parent->right))
99 return true;
100 if (prev == parent->right &&
101 is_upper(var, parent->left))
102 return true;
104 prev = parent;
106 if (is_if_else_clamp_stmt(var, prev))
107 return true;
109 return false;
112 static void match_condition(struct expression *expr)
114 struct expression *left, *right;
115 char *name;
116 int op;
118 if (expr->type != EXPR_COMPARE)
119 return;
121 if (!flip_order(expr, &left, &op, &right))
122 return;
124 if (op != '<' &&
125 op != SPECIAL_UNSIGNED_LT)
126 return;
128 if (!expr_is_zero(right))
129 return;
131 if (op != SPECIAL_UNSIGNED_LT && !expr_unsigned(left))
132 return;
134 if (has_upper_bound(left, expr))
135 return;
137 name = expr_to_str(left);
138 sm_warning("unsigned '%s' is never less than zero.", name);
139 free_string(name);
142 void check_unsigned_lt_zero(int id)
144 my_id = id;
146 add_hook(&match_condition, CONDITION_HOOK);