param_key: fix container of when no struct member is referenced
[smatch.git] / check_zero_to_err_ptr.c
blob53dd8291a22e893fd68c8d2d795d0672d21410c7
1 /*
2 * Copyright (C) 2013 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
18 #include "smatch.h"
19 #include "smatch_extra.h"
20 #include "smatch_slist.h"
22 static int my_id;
24 static bool is_select_assign(struct expression *expr)
26 /* select assignments are faked in smatch_conditions.c */
27 expr = expr_get_parent_expr(expr);
28 if (!expr || expr->type != EXPR_ASSIGNMENT)
29 return false;
30 expr = expr_get_parent_expr(expr);
31 if (!expr)
32 return false;
33 if (expr->type == EXPR_CONDITIONAL ||
34 expr->type == EXPR_SELECT)
35 return true;
36 return false;
39 static int is_comparison_call(struct expression *expr)
41 expr = expr_get_parent_expr(expr);
42 if (!expr || expr->type != EXPR_COMPARE)
43 return 0;
44 if (expr->op != SPECIAL_EQUAL && expr->op != SPECIAL_NOTEQUAL)
45 return 0;
46 return 1;
49 static int next_line_is_if(struct expression *expr)
51 struct expression *next;
53 if (!__next_stmt || __next_stmt->type != STMT_IF)
54 return 0;
56 next = strip_expr(__next_stmt->if_conditional);
57 while (next->type == EXPR_PREOP && next->op == '!')
58 next = strip_expr(next->unop);
59 if (expr_equiv(expr, next))
60 return 1;
61 return 0;
64 static int next_line_checks_IS_ERR(struct expression *call, struct expression *arg)
66 struct expression *next;
67 struct expression *tmp;
69 tmp = expr_get_parent_expr(call);
70 if (tmp && tmp->type == EXPR_ASSIGNMENT) {
71 if (next_line_checks_IS_ERR(NULL, tmp->left))
72 return 1;
75 if (!__next_stmt || __next_stmt->type != STMT_IF)
76 return 0;
78 next = strip_expr(__next_stmt->if_conditional);
79 while (next->type == EXPR_PREOP && next->op == '!')
80 next = strip_expr(next->unop);
81 if (!next || next->type != EXPR_CALL)
82 return 0;
83 if (next->fn->type != EXPR_SYMBOL || !next->fn->symbol ||
84 !next->fn->symbol->ident ||
85 (strcmp(next->fn->symbol->ident->name, "IS_ERR") != 0 &&
86 strcmp(next->fn->symbol->ident->name, "IS_ERR_OR_NULL") != 0))
87 return 0;
88 next = get_argument_from_call_expr(next->args, 0);
89 return expr_equiv(next, arg);
92 static int is_non_zero_int(struct range_list *rl)
94 struct data_range *tmp;
95 int cnt = -1;
97 FOR_EACH_PTR(rl, tmp) {
98 cnt++;
100 if (cnt == 0) {
101 if (tmp->min.value == INT_MIN &&
102 tmp->max.value == -1)
103 continue;
104 } else if (cnt == 1) {
105 if (tmp->min.value == 1 &&
106 tmp->max.value == INT_MAX)
107 return 1;
109 return 0;
110 } END_FOR_EACH_PTR(tmp);
111 return 0;
114 static int is_valid_ptr(sval_t sval)
116 if (sval.value == INT_MIN || sval.value == INT_MAX)
117 return 0;
119 if (sval_cmp(valid_ptr_min_sval, sval) <= 0 &&
120 sval_cmp(valid_ptr_max_sval, sval) >= 0) {
121 return 1;
123 return 0;
126 static int has_distinct_zero(struct range_list *rl)
128 struct data_range *tmp;
130 FOR_EACH_PTR(rl, tmp) {
131 if (tmp->min.value == 0 || tmp->max.value == 0)
132 return 1;
133 } END_FOR_EACH_PTR(tmp);
134 return 0;
137 static void match_err_ptr(const char *fn, struct expression *expr, void *data)
139 struct expression *arg_expr;
140 struct sm_state *sm, *tmp;
142 if (is_impossible_path())
143 return;
145 arg_expr = get_argument_from_call_expr(expr->args, 0);
146 sm = get_sm_state_expr(SMATCH_EXTRA, arg_expr);
147 if (!sm)
148 return;
150 if (is_comparison_call(expr))
151 return;
152 if (is_select_assign(expr))
153 return;
155 if (next_line_checks_IS_ERR(expr, arg_expr))
156 return;
157 if (strcmp(fn, "ERR_PTR") == 0 &&
158 next_line_is_if(arg_expr))
159 return;
161 FOR_EACH_PTR(sm->possible, tmp) {
162 if (!estate_rl(tmp->state))
163 continue;
164 if (is_non_zero_int(estate_rl(tmp->state)))
165 continue;
166 if (has_distinct_zero(estate_rl(tmp->state))) {
167 sm_warning("passing zero to '%s'", fn);
168 return;
170 if (strcmp(fn, "PTR_ERR") != 0)
171 continue;
172 if (is_valid_ptr(estate_min(tmp->state)) &&
173 is_valid_ptr(estate_max(tmp->state))) {
174 sm_warning("passing a valid pointer to '%s'", fn);
175 return;
177 } END_FOR_EACH_PTR(tmp);
180 void check_zero_to_err_ptr(int id)
182 if (option_project != PROJ_KERNEL)
183 return;
185 my_id = id;
186 add_function_hook("ERR_PTR", &match_err_ptr, NULL);
187 add_function_hook("ERR_CAST", &match_err_ptr, NULL);
188 add_function_hook("PTR_ERR", &match_err_ptr, NULL);