get_type() fix crash on getting pointer types.
[smatch.git] / check_err_ptr_deref.c
blob256ab77bb9125304106a6a8fbd23d9325c3545d4
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);
38 static void match_checked(const char *fn, struct expression *call_expr,
39 struct expression *assign_expr, void *unused)
41 struct expression *arg;
43 arg = get_argument_from_call_expr(call_expr->args, 0);
44 arg = strip_expr(arg);
45 while (arg->type == EXPR_ASSIGNMENT)
46 arg = strip_expr(arg->left);
47 set_state_expr(my_id, arg, &checked);
50 static void match_err(const char *fn, struct expression *call_expr,
51 struct expression *assign_expr, void *unused)
53 struct expression *arg;
55 arg = get_argument_from_call_expr(call_expr->args, 0);
56 arg = strip_expr(arg);
57 while (arg->type == EXPR_ASSIGNMENT)
58 arg = strip_expr(arg->left);
59 set_state_expr(my_id, arg, &err_ptr);
62 static void match_dereferences(struct expression *expr)
64 struct sm_state *sm;
66 if (expr->type != EXPR_PREOP)
67 return;
68 expr = strip_expr(expr->unop);
70 sm = get_sm_state_expr(my_id, expr);
71 check_is_err_ptr(sm);
74 static void register_err_ptr_funcs(void)
76 struct token *token;
77 const char *func;
79 token = get_tokens_file("kernel.returns_err_ptr");
80 if (!token)
81 return;
82 if (token_type(token) != TOKEN_STREAMBEGIN)
83 return;
84 token = token->next;
85 while (token_type(token) != TOKEN_STREAMEND) {
86 if (token_type(token) != TOKEN_IDENT)
87 return;
88 func = show_ident(token->ident);
89 add_function_assign_hook(func, &match_returns_err_ptr, NULL);
90 token = token->next;
92 clear_token_alloc();
95 static void match_err_ptr(const char *fn, struct expression *expr, void *unused)
97 struct expression *arg;
98 struct sm_state *sm;
99 struct sm_state *tmp;
100 long long tmp_min;
101 long long tmp_max;
102 long long min = whole_range.max;
103 long long max = whole_range.min;
105 arg = get_argument_from_call_expr(expr->args, 0);
106 sm = get_sm_state_expr(SMATCH_EXTRA, arg);
107 if (!sm)
108 return;
109 FOR_EACH_PTR(sm->possible, tmp) {
110 tmp_min = get_dinfo_min(get_dinfo(tmp->state));
111 if (tmp_min != whole_range.min && tmp_min < min)
112 min = tmp_min;
113 tmp_max = get_dinfo_max(get_dinfo(tmp->state));
114 if (tmp_max != whole_range.max && tmp_max > max)
115 max = tmp_max;
116 } END_FOR_EACH_PTR(tmp);
117 if (min < -4095)
118 sm_msg("error: %lld too low for ERR_PTR", min);
119 if (max > 0)
120 sm_msg("error: passing non neg %lld to ERR_PTR", max);
123 static void match_ptr_err(const char *fn, struct expression *expr, void *unused)
125 struct expression *arg;
126 struct expression *right;
128 right = strip_expr(expr->right);
129 arg = get_argument_from_call_expr(right->args, 0);
130 if (get_state_expr(my_id, arg) == &err_ptr) {
131 set_state_expr(SMATCH_EXTRA, expr->left, alloc_extra_state_range(-4095, -1));
135 void check_err_ptr_deref(int id)
137 if (option_project != PROJ_KERNEL)
138 return;
140 my_id = id;
141 return_implies_state("IS_ERR", 0, 0, &match_checked, NULL);
142 return_implies_state("IS_ERR", 1, 1, &match_err, NULL);
143 register_err_ptr_funcs();
144 add_hook(&match_dereferences, DEREF_HOOK);
145 add_function_hook("ERR_PTR", &match_err_ptr, NULL);
146 add_function_assign_hook("PTR_ERR", &match_ptr_err, NULL);