The nullify_path() here is a bug. It over-writes all the states from
[smatch.git] / check_derefed_params.c
blob024d3019c862385315f0d5dc134539edaf74b728
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 enum states {
16 ARGUMENT,
17 ISNULL,
18 NONNULL,
19 IGNORE,
22 struct param {
23 struct symbol *sym;
24 int used;
26 ALLOCATOR(param, "parameters");
27 #define MAX_PARAMS 16
28 struct param *params[MAX_PARAMS];
30 static int merge_func(const char *name, struct symbol *sym, int s1, int s2)
32 if (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;
86 deref = get_variable_from_expr(expr->deref, &sym);
87 switch(get_state("", my_id, sym)) {
88 case ARGUMENT:
89 print_unchecked_param(sym);
90 /* this doesn't actually work because we'll still see
91 the same variable get derefed on other paths */
92 set_state("", my_id, sym, IGNORE);
93 break;
94 case ISNULL:
95 smatch_msg("Error dereferencing NULL: %s", deref);
96 break;
97 default:
98 break;
102 static void match_function_call_after(struct expression *expr)
104 struct expression *tmp;
105 struct symbol *sym;
106 int state;
108 FOR_EACH_PTR(expr->args, tmp) {
109 if (tmp->op == '&') {
110 get_variable_from_expr(tmp, &sym);
111 state = get_state("", my_id, sym);
112 if (state != NOTFOUND) {
113 set_state("", my_id, sym, NONNULL);
116 } END_FOR_EACH_PTR(tmp);
119 static void match_assign(struct expression *expr)
121 int state;
123 /* Since we're only tracking arguments, we only want
124 EXPR_SYMBOLs. */
125 if (expr->left->type != EXPR_SYMBOL)
126 return;
127 state = get_state("", my_id, expr->left->symbol);
128 if (state == NOTFOUND)
129 return;
130 /* probably it's non null */
131 set_state("", my_id, expr->left->symbol, NONNULL);
134 static void match_condition(struct expression *expr)
136 switch(expr->type) {
137 case EXPR_COMPARE: {
138 struct symbol *sym = NULL;
140 if (expr->left->type == EXPR_SYMBOL) {
141 sym = expr->left->symbol;
142 if (expr->right->type != EXPR_VALUE
143 || expr->right->value != 0)
144 return;
146 if (expr->right->type == EXPR_SYMBOL) {
147 sym = expr->right->symbol;
148 if (expr->left->type != EXPR_VALUE
149 || expr->left->value != 0)
150 return;
152 if (!sym)
153 return;
155 if (expr->op == SPECIAL_EQUAL)
156 set_true_false_states("", my_id, sym, ISNULL,
157 NONNULL);
158 else if (expr->op == SPECIAL_NOTEQUAL)
159 set_true_false_states("", my_id, sym, NONNULL,
160 ISNULL);
161 return;
163 case EXPR_SYMBOL:
164 if (get_state("", my_id, expr->symbol) == ARGUMENT) {
165 set_true_false_states("", my_id, expr->symbol,
166 NONNULL, ISNULL);
168 return;
169 default:
170 return;
174 static void end_of_func_cleanup(struct symbol *sym)
176 int i = 0;
178 while (params[i]) {
179 __free_param(params[i]);
180 i++;
184 void register_derefed_params(int id)
186 my_id = id;
187 add_merge_hook(my_id, &merge_func);
188 add_hook(&match_function_def, FUNC_DEF_HOOK);
189 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
190 add_hook(&match_deref, DEREF_HOOK);
191 add_hook(&match_assign, ASSIGNMENT_HOOK);
192 add_hook(&match_condition, CONDITION_HOOK);
193 add_hook(&end_of_func_cleanup, END_FUNC_HOOK);