Handle assignmeents inside conditions better.
[smatch.git] / check_derefed_params.c
blob5eb80025acac989f54a4c63f53c074391a4cb90c
1 /*
2 * sparse/check_deference.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "token.h"
11 #include "smatch.h"
13 static int my_id;
15 STATE(argument);
16 STATE(ignore);
17 STATE(isnull);
18 STATE(nonnull);
20 struct param {
21 struct symbol *sym;
22 int used;
24 ALLOCATOR(param, "parameters");
25 #define MAX_PARAMS 16
26 struct param *params[MAX_PARAMS];
28 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
29 struct smatch_state *s1,
30 struct smatch_state *s2)
32 if (s1 == &ignore || s2 == &ignore)
33 return &ignore;
34 if (s1 == &argument)
35 return s2;
36 return &undefined;
39 static struct param *new_param(struct symbol *arg)
41 struct param *new;
43 new = __alloc_param(0);
44 if (!new) {
45 printf("Internal error: Unable to allocate memory in new_param()\n");
46 exit(1);
48 new->sym = arg;
49 new->used = 0;
50 return new;
53 static void match_function_def(struct symbol *sym)
55 struct symbol *arg;
56 int i = 0;
57 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
58 set_state("", my_id, arg, &argument);
59 params[i] = new_param(arg);
60 i++;
61 if (i >= MAX_PARAMS - 1) {
62 printf("Error function has too many params.\n");
63 break;
65 } END_FOR_EACH_PTR(arg);
66 params[i] = NULL;
69 static void print_unchecked_param(struct symbol *sym) {
70 int i = 0;
72 while (params[i]) {
73 if (params[i]->sym == sym && !params[i]->used) {
74 smatch_msg("unchecked param: %s %d", get_function(),
75 i);
77 i++;
81 static void match_deref(struct expression *expr)
83 char *deref = NULL;
84 struct symbol *sym = NULL;
85 struct smatch_state *state;
87 if (strcmp(show_special(expr->deref->op), "*"))
88 return;
90 deref = get_variable_from_expr_simple(expr->deref->unop, &sym);
91 if (!deref)
92 return;
93 state = get_state("", my_id, sym);
94 if (state == &argument) {
95 print_unchecked_param(sym);
96 /* this doesn't actually work because we'll still see
97 the same variable get derefed on other paths */
98 set_state("", my_id, sym, &ignore);
99 } else if (state == &isnull)
100 smatch_msg("Error dereferencing NULL: %s", deref);
103 static void match_function_call_after(struct expression *expr)
105 struct expression *tmp;
106 struct symbol *sym;
107 struct smatch_state *state;
109 FOR_EACH_PTR(expr->args, tmp) {
110 if (tmp->op == '&') {
111 get_variable_from_expr(tmp, &sym);
112 state = get_state("", my_id, sym);
113 if (state) {
114 set_state("", my_id, sym, &nonnull);
117 } END_FOR_EACH_PTR(tmp);
120 static void match_assign(struct expression *expr)
122 struct smatch_state *state;
124 /* Since we're only tracking arguments, we only want
125 EXPR_SYMBOLs. */
126 if (expr->left->type != EXPR_SYMBOL)
127 return;
128 state = get_state("", my_id, expr->left->symbol);
129 if (!state)
130 return;
131 /* probably it's non null */
132 set_state("", my_id, expr->left->symbol, &nonnull);
135 static void match_condition(struct expression *expr)
137 switch(expr->type) {
138 case EXPR_COMPARE: {
139 struct symbol *sym = NULL;
141 if (expr->left->type == EXPR_SYMBOL) {
142 sym = expr->left->symbol;
143 if (expr->right->type != EXPR_VALUE
144 || expr->right->value != 0)
145 return;
147 if (expr->right->type == EXPR_SYMBOL) {
148 sym = expr->right->symbol;
149 if (expr->left->type != EXPR_VALUE
150 || expr->left->value != 0)
151 return;
153 if (!sym)
154 return;
156 if (expr->op == SPECIAL_EQUAL)
157 set_true_false_states("", my_id, sym, &isnull,
158 &nonnull);
159 else if (expr->op == SPECIAL_NOTEQUAL)
160 set_true_false_states("", my_id, sym, &nonnull,
161 &isnull);
162 return;
164 case EXPR_SYMBOL:
165 if (get_state("", my_id, expr->symbol) == &argument) {
166 set_true_false_states("", my_id, expr->symbol,
167 &nonnull, &isnull);
169 return;
170 default:
171 return;
175 static void end_of_func_cleanup(struct symbol *sym)
177 int i = 0;
179 while (params[i]) {
180 __free_param(params[i]);
181 i++;
185 void register_derefed_params(int id)
187 my_id = id;
188 add_merge_hook(my_id, &merge_func);
189 add_hook(&match_function_def, FUNC_DEF_HOOK);
190 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
191 add_hook(&match_deref, DEREF_HOOK);
192 add_hook(&match_assign, ASSIGNMENT_HOOK);
193 add_hook(&match_condition, CONDITION_HOOK);
194 add_hook(&end_of_func_cleanup, END_FUNC_HOOK);