sval: update check_deref.c
[smatch.git] / check_err_ptr_deref.c
blob9077c597ff385f6bd571ead846801ee59bd17683
1 /*
2 * sparse/check_err_ptr_deref.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "smatch.h"
11 #include "smatch_slist.h"
12 #include "smatch_extra.h"
14 static int my_id;
16 STATE(err_ptr);
17 STATE(checked);
19 static void ok_to_use(struct sm_state *sm)
21 if (sm->state != &checked)
22 set_state(my_id, sm->name, sm->sym, &checked);
25 static void check_is_err_ptr(struct sm_state *sm)
27 if (!sm)
28 return;
30 if (slist_has_state(sm->possible, &err_ptr)) {
31 sm_msg("error: '%s' dereferencing possible ERR_PTR()",
32 sm->name);
33 set_state(my_id, sm->name, sm->sym, &checked);
37 static void match_returns_err_ptr(const char *fn, struct expression *expr,
38 void *info)
40 set_state_expr(my_id, expr->left, &err_ptr);
44 static void match_checked(const char *fn, struct expression *call_expr,
45 struct expression *assign_expr, void *unused)
47 struct expression *arg;
49 arg = get_argument_from_call_expr(call_expr->args, 0);
50 arg = strip_expr(arg);
51 while (arg->type == EXPR_ASSIGNMENT)
52 arg = strip_expr(arg->left);
53 set_state_expr(my_id, arg, &checked);
56 static void match_err(const char *fn, struct expression *call_expr,
57 struct expression *assign_expr, void *unused)
59 struct expression *arg;
61 arg = get_argument_from_call_expr(call_expr->args, 0);
62 arg = strip_expr(arg);
63 while (arg->type == EXPR_ASSIGNMENT)
64 arg = strip_expr(arg->left);
65 set_state_expr(my_id, arg, &err_ptr);
68 static void match_dereferences(struct expression *expr)
70 struct sm_state *sm;
72 if (expr->type != EXPR_PREOP)
73 return;
74 expr = strip_expr(expr->unop);
76 sm = get_sm_state_expr(my_id, expr);
77 check_is_err_ptr(sm);
80 static void match_condition(struct expression *expr)
82 if (expr->type == EXPR_ASSIGNMENT) {
83 match_condition(expr->right);
84 match_condition(expr->left);
86 if (!get_state_expr(my_id, expr))
87 return;
88 /* If we know the variable is zero that means it's not an ERR_PTR */
89 set_true_false_states_expr(my_id, expr, NULL, &checked);
92 static void register_err_ptr_funcs(void)
94 struct token *token;
95 const char *func;
97 token = get_tokens_file("kernel.returns_err_ptr");
98 if (!token)
99 return;
100 if (token_type(token) != TOKEN_STREAMBEGIN)
101 return;
102 token = token->next;
103 while (token_type(token) != TOKEN_STREAMEND) {
104 if (token_type(token) != TOKEN_IDENT)
105 return;
106 func = show_ident(token->ident);
107 add_function_assign_hook(func, &match_returns_err_ptr, NULL);
108 token = token->next;
110 clear_token_alloc();
113 static void match_err_ptr(const char *fn, struct expression *expr, void *unused)
115 struct expression *arg;
116 struct sm_state *sm;
117 struct sm_state *tmp;
118 long long tmp_min;
119 long long tmp_max;
120 long long min = whole_range.max;
121 long long max = whole_range.min;
123 arg = get_argument_from_call_expr(expr->args, 0);
124 sm = get_sm_state_expr(SMATCH_EXTRA, arg);
125 if (!sm)
126 return;
127 FOR_EACH_PTR(sm->possible, tmp) {
128 tmp_min = estate_min(tmp->state);
129 if (tmp_min != whole_range.min && tmp_min < min)
130 min = tmp_min;
131 tmp_max = estate_max(tmp->state);
132 if (tmp_max != whole_range.max && tmp_max > max)
133 max = tmp_max;
134 } END_FOR_EACH_PTR(tmp);
135 if (min < -4095)
136 sm_msg("error: %lld too low for ERR_PTR", min);
137 if (max > 0)
138 sm_msg("error: passing non neg %lld to ERR_PTR", max);
141 void check_err_ptr_deref(int id)
143 if (option_project != PROJ_KERNEL)
144 return;
146 my_id = id;
147 return_implies_state("IS_ERR", 0, 0, &match_checked, NULL);
148 return_implies_state("IS_ERR", 1, 1, &match_err, NULL);
149 return_implies_state("IS_ERR_OR_NULL", 0, 0, &match_checked, NULL);
150 return_implies_state("IS_ERR_OR_NULL", 1, 1, &match_err, NULL);
151 return_implies_state("PTR_RET", 0, 0, &match_checked, NULL);
152 return_implies_state("PTR_RET", -4096, -1, &match_err, NULL);
153 register_err_ptr_funcs();
154 add_hook(&match_dereferences, DEREF_HOOK);
155 add_function_hook("ERR_PTR", &match_err_ptr, NULL);
156 add_hook(&match_condition, CONDITION_HOOK);
157 add_modification_hook(my_id, &ok_to_use);