flow: fix some ordering bugs in handling DEREFs and PREOPs
[smatch.git] / check_unsigned_lt_zero.c
blobe627540144553919c99f3b852143c4a1d0967059
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 is_allowed_zero(struct expression *expr)
87 char *macro;
89 macro = get_macro_name(expr->pos);
90 if (!macro)
91 return false;
92 if (strcmp(macro, "ARRAY_SIZE") == 0 ||
93 strcmp(macro, "DPMCP_MIN_VER_MINOR") == 0 ||
94 strcmp(macro, "KASAN_SHADOW_OFFSET") == 0 ||
95 strcmp(macro, "NF_CT_HELPER_BUILD_BUG_ON") == 0 ||
96 strcmp(macro, "TEST_ONE_SHIFT") == 0)
97 return true;
98 return false;
101 static bool has_upper_bound(struct expression *var, struct expression *expr)
103 struct expression *parent, *prev;
105 parent = expr;
106 prev = expr;
107 while ((parent = expr_get_parent_expr(parent))) {
108 if (parent->type == EXPR_LOGICAL &&
109 parent->op == SPECIAL_LOGICAL_AND)
110 break;
111 if (parent->type == EXPR_LOGICAL &&
112 parent->op == SPECIAL_LOGICAL_OR) {
113 if (prev == parent->left &&
114 is_upper(var, parent->right))
115 return true;
116 if (prev == parent->right &&
117 is_upper(var, parent->left))
118 return true;
120 prev = parent;
122 if (is_if_else_clamp_stmt(var, prev))
123 return true;
125 return false;
128 static void match_condition(struct expression *expr)
130 struct expression *left, *right;
131 char *name;
132 int op;
134 if (expr->type != EXPR_COMPARE)
135 return;
137 if (!flip_order(expr, &left, &op, &right))
138 return;
140 if (op != '<' &&
141 op != SPECIAL_UNSIGNED_LT)
142 return;
144 if (!expr_is_zero(right))
145 return;
147 if (is_allowed_zero(right))
148 return;
150 if (op != SPECIAL_UNSIGNED_LT && !expr_unsigned(left))
151 return;
153 if (has_upper_bound(left, expr))
154 return;
156 name = expr_to_str(left);
157 sm_warning("unsigned '%s' is never less than zero.", name);
158 free_string(name);
161 void check_unsigned_lt_zero(int id)
163 my_id = id;
165 add_hook(&match_condition, CONDITION_HOOK);