Redo checking for out of range args to ERR_PTR()
[smatch.git] / check_err_ptr_deref.c
blob1723f055a59cb46425d1de7706904cff3149e211
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 (slist_has_state(sm->possible, &err_ptr)) {
22 smatch_msg("error: '%s' dereferencing possible ERR_PTR()",
23 sm->name);
24 set_state(sm->name, my_id, sm->sym, &checked);
28 static void match_returns_err_ptr(const char *fn, struct expression *expr,
29 void *info)
31 char *left_name = NULL;
32 struct symbol *left_sym;
34 left_name = get_variable_from_expr(expr->left, &left_sym);
35 if (!left_name || !left_sym)
36 goto free;
37 set_state(left_name, my_id, left_sym, &err_ptr);
38 free:
39 free_string(left_name);
42 static void match_is_err(const char *fn, struct expression *expr,
43 void *data)
45 char *name;
46 struct symbol *sym;
48 expr = get_argument_from_call_expr(expr->args, 0);
49 if (expr->type == EXPR_ASSIGNMENT)
50 expr = expr->left;
51 name = get_variable_from_expr(expr, &sym);
52 if (!name || !sym)
53 goto free;
54 set_true_false_states(name, my_id, sym, &err_ptr, &checked);
55 free:
56 free_string(name);
59 static void match_dereferences(struct expression *expr)
61 char *deref = NULL;
62 struct symbol *sym = NULL;
63 struct sm_state *sm;
65 deref = get_variable_from_expr(expr->deref->unop, &sym);
66 if (!deref || !sym)
67 goto free;
69 sm = get_sm_state(deref, my_id, sym);
70 if (sm)
71 check_is_err_ptr(sm);
72 free:
73 free_string(deref);
76 static void register_err_ptr_funcs(void)
78 struct token *token;
79 const char *func;
81 token = get_tokens_file("kernel.returns_err_ptr");
82 if (!token)
83 return;
84 if (token_type(token) != TOKEN_STREAMBEGIN)
85 return;
86 token = token->next;
87 while (token_type(token) != TOKEN_STREAMEND) {
88 if (token_type(token) != TOKEN_IDENT)
89 return;
90 func = show_ident(token->ident);
91 add_function_assign_hook(func, &match_returns_err_ptr, NULL);
92 token = token->next;
94 clear_token_alloc();
97 static void match_err_ptr(const char *fn, struct expression *expr, void *info)
99 struct expression *arg;
100 char *name;
101 struct symbol *sym;
102 struct sm_state *sm;
103 struct sm_state *tmp;
104 long long tmp_min;
105 long long tmp_max;
106 long long min = whole_range.max;
107 long long max = whole_range.min;
109 arg = get_argument_from_call_expr(expr->args, 0);
110 name = get_variable_from_expr(arg, &sym);
111 if (!name || !sym)
112 goto free;
113 sm = get_sm_state(name, SMATCH_EXTRA, sym);
114 if (!sm)
115 goto free;
116 FOR_EACH_PTR(sm->possible, tmp) {
117 tmp_min = get_dinfo_min((struct data_info *)tmp->state->data);
118 if (tmp_min != whole_range.min && tmp_min < min)
119 min = tmp_min;
120 tmp_max = get_dinfo_max((struct data_info *)tmp->state->data);
121 if (tmp_max != whole_range.max && tmp_max > max)
122 max = tmp_max;
123 } END_FOR_EACH_PTR(tmp);
124 if (min < -4095)
125 smatch_msg("error: %lld too low for ERR_PTR", min);
126 if (max > 0)
127 smatch_msg("error: passing non neg %lld to ERR_PTR", max);
128 free:
129 free_string(name);
132 void check_err_ptr_deref(int id)
134 my_id = id;
135 add_conditional_hook("IS_ERR", &match_is_err, NULL);
136 register_err_ptr_funcs();
137 add_hook(&match_dereferences, DEREF_HOOK);
138 add_function_hook("ERR_PTR", &match_err_ptr, NULL);