add a check for passing stack variables to dma functions
[smatch.git] / check_err_ptr_deref.c
blob9d9689c18294453e1870d1f791eca06741842b69
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 if (expr->type != EXPR_PREOP)
51 return;
52 expr = strip_expr(expr->unop);
54 sm = get_sm_state_expr(my_id, expr);
55 check_is_err_ptr(sm);
58 static void register_err_ptr_funcs(void)
60 struct token *token;
61 const char *func;
63 token = get_tokens_file("kernel.returns_err_ptr");
64 if (!token)
65 return;
66 if (token_type(token) != TOKEN_STREAMBEGIN)
67 return;
68 token = token->next;
69 while (token_type(token) != TOKEN_STREAMEND) {
70 if (token_type(token) != TOKEN_IDENT)
71 return;
72 func = show_ident(token->ident);
73 add_function_assign_hook(func, &match_returns_err_ptr, NULL);
74 token = token->next;
76 clear_token_alloc();
79 static void match_err_ptr(const char *fn, struct expression *expr, void *unused)
81 struct expression *arg;
82 struct sm_state *sm;
83 struct sm_state *tmp;
84 long long tmp_min;
85 long long tmp_max;
86 long long min = whole_range.max;
87 long long max = whole_range.min;
89 arg = get_argument_from_call_expr(expr->args, 0);
90 sm = get_sm_state_expr(SMATCH_EXTRA, arg);
91 if (!sm)
92 return;
93 FOR_EACH_PTR(sm->possible, tmp) {
94 tmp_min = get_dinfo_min((struct data_info *)tmp->state->data);
95 if (tmp_min != whole_range.min && tmp_min < min)
96 min = tmp_min;
97 tmp_max = get_dinfo_max((struct data_info *)tmp->state->data);
98 if (tmp_max != whole_range.max && tmp_max > max)
99 max = tmp_max;
100 } END_FOR_EACH_PTR(tmp);
101 if (min < -4095)
102 sm_msg("error: %lld too low for ERR_PTR", min);
103 if (max > 0)
104 sm_msg("error: passing non neg %lld to ERR_PTR", max);
107 static void match_ptr_err(const char *fn, struct expression *expr, void *unused)
109 struct expression *arg;
110 struct expression *right;
112 right = strip_expr(expr->right);
113 arg = get_argument_from_call_expr(right->args, 0);
114 if (get_state_expr(my_id, arg) == &err_ptr) {
115 set_state_expr(SMATCH_EXTRA, expr->left, alloc_extra_state_range(-4095, -1));
119 void check_err_ptr_deref(int id)
121 if (option_project != PROJ_KERNEL)
122 return;
124 my_id = id;
125 set_default_state(my_id, &checked);
126 add_conditional_hook("IS_ERR", &match_is_err, NULL);
127 register_err_ptr_funcs();
128 add_hook(&match_dereferences, DEREF_HOOK);
129 add_function_hook("ERR_PTR", &match_err_ptr, NULL);
130 add_function_assign_hook("PTR_ERR", &match_ptr_err, NULL);