small clean up.
[smatch.git] / check_err_ptr_deref.c
blob76cd538627abae08eaf2c66a65e2594130929aa7
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 check_is_err_ptr(struct sm_state *sm)
21 if (!sm)
22 return;
24 if (slist_has_state(sm->possible, &err_ptr)) {
25 sm_msg("error: '%s' dereferencing possible ERR_PTR()",
26 sm->name);
27 set_state(my_id, sm->name, sm->sym, &checked);
31 static void match_returns_err_ptr(const char *fn, struct expression *expr,
32 void *info)
34 set_state_expr(my_id, expr->left, &err_ptr);
37 static void match_is_err(const char *fn, struct expression *expr,
38 void *data)
40 expr = get_argument_from_call_expr(expr->args, 0);
41 if (expr->type == EXPR_ASSIGNMENT)
42 expr = expr->left;
43 set_true_false_states_expr(my_id, expr, &err_ptr, &checked);
46 static void match_dereferences(struct expression *expr)
48 struct sm_state *sm;
50 sm = get_sm_state_expr(my_id, expr->deref->unop);
51 check_is_err_ptr(sm);
54 static void register_err_ptr_funcs(void)
56 struct token *token;
57 const char *func;
59 token = get_tokens_file("kernel.returns_err_ptr");
60 if (!token)
61 return;
62 if (token_type(token) != TOKEN_STREAMBEGIN)
63 return;
64 token = token->next;
65 while (token_type(token) != TOKEN_STREAMEND) {
66 if (token_type(token) != TOKEN_IDENT)
67 return;
68 func = show_ident(token->ident);
69 add_function_assign_hook(func, &match_returns_err_ptr, NULL);
70 token = token->next;
72 clear_token_alloc();
75 static void match_err_ptr(const char *fn, struct expression *expr, void *unused)
77 struct expression *arg;
78 struct sm_state *sm;
79 struct sm_state *tmp;
80 long long tmp_min;
81 long long tmp_max;
82 long long min = whole_range.max;
83 long long max = whole_range.min;
85 arg = get_argument_from_call_expr(expr->args, 0);
86 sm = get_sm_state_expr(SMATCH_EXTRA, arg);
87 if (!sm)
88 return;
89 FOR_EACH_PTR(sm->possible, tmp) {
90 tmp_min = get_dinfo_min((struct data_info *)tmp->state->data);
91 if (tmp_min != whole_range.min && tmp_min < min)
92 min = tmp_min;
93 tmp_max = get_dinfo_max((struct data_info *)tmp->state->data);
94 if (tmp_max != whole_range.max && tmp_max > max)
95 max = tmp_max;
96 } END_FOR_EACH_PTR(tmp);
97 if (min < -4095)
98 sm_msg("error: %lld too low for ERR_PTR", min);
99 if (max > 0)
100 sm_msg("error: passing non neg %lld to ERR_PTR", max);
103 static void match_ptr_err(const char *fn, struct expression *expr, void *unused)
105 struct expression *arg;
106 struct expression *right;
108 right = strip_expr(expr->right);
109 arg = get_argument_from_call_expr(right->args, 0);
110 if (get_state_expr(my_id, arg) == &err_ptr) {
111 set_state_expr(SMATCH_EXTRA, expr->left, alloc_extra_state_range(-4095, -1));
115 void check_err_ptr_deref(int id)
117 my_id = id;
118 set_default_state(my_id, &checked);
119 add_conditional_hook("IS_ERR", &match_is_err, NULL);
120 register_err_ptr_funcs();
121 add_hook(&match_dereferences, DEREF_HOOK);
122 add_function_hook("ERR_PTR", &match_err_ptr, NULL);
123 add_function_assign_hook("PTR_ERR", &match_ptr_err, NULL);