function_hooks: improve how function assignments are handled
[smatch.git] / check_double_checking.c
blobe5c5c785b6e5adcd0038aa398fba750c7885954a
1 /*
2 * Copyright (C) 2014 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
18 #include "smatch.h"
19 #include "smatch_slist.h"
21 static int my_id;
23 STATE(checked);
24 STATE(modified);
26 struct stree *to_check;
28 static void set_modified(struct sm_state *sm, struct expression *mod_expr)
30 set_state(my_id, sm->name, sm->sym, &modified);
33 static void match_condition(struct expression *expr)
35 struct smatch_state *state;
36 sval_t dummy;
37 int is_true;
38 char *name;
40 if (get_value(expr, &dummy))
41 return;
43 if (get_macro_name(expr->pos))
44 return;
46 // FIXME: needed?
47 if (implied_condition_true(expr))
48 is_true = 1;
49 else if (implied_condition_false(expr))
50 is_true = 0;
51 else
52 return;
54 state = get_stored_condition(expr);
55 if (!state || !state->data)
56 return;
57 if (get_macro_name(((struct expression *)state->data)->pos))
58 return;
61 * we allow double checking for NULL because people do this all the time
62 * and trying to stop them is a losers' battle.
64 if (is_pointer(expr) && is_true)
65 return;
67 if (definitely_inside_loop()) {
68 struct symbol *sym;
70 if (__inline_fn)
71 return;
73 name = expr_to_var_sym(expr, &sym);
74 if (!name)
75 return;
76 set_state_expr(my_id, expr, &checked);
77 set_state_stree(&to_check, my_id, name, sym, &checked);
78 free_string(name);
79 return;
82 name = expr_to_str(expr);
83 sm_msg("warn: we tested '%s' before and it was '%s'", name, state->name);
84 free_string(name);
87 int get_check_line(struct sm_state *sm)
89 struct sm_state *tmp;
91 FOR_EACH_PTR(sm->possible, tmp) {
92 if (tmp->state == &checked)
93 return tmp->line;
94 } END_FOR_EACH_PTR(tmp);
96 return get_lineno();
99 static void after_loop(struct statement *stmt)
101 struct sm_state *check, *sm;
103 if (!stmt || stmt->type != STMT_ITERATOR)
104 return;
105 if (definitely_inside_loop())
106 return;
107 if (__inline_fn)
108 return;
110 FOR_EACH_SM(to_check, check) {
111 continue;
112 sm = get_sm_state(my_id, check->name, check->sym);
113 continue;
114 if (!sm)
115 continue;
116 if (slist_has_state(sm->possible, &modified))
117 continue;
119 sm_printf("%s:%d %s() ", get_filename(), get_check_line(sm), get_function());
120 sm_printf("warn: we tested '%s' already\n", check->name);
121 } END_FOR_EACH_SM(check);
123 free_stree(&to_check);
126 static void match_func_end(struct symbol *sym)
128 if (__inline_fn)
129 return;
130 if (to_check)
131 sm_msg("debug: odd... found an function without an end.");
132 free_stree(&to_check);
135 void check_double_checking(int id)
137 my_id = id;
139 if (!option_spammy)
140 return;
142 add_hook(&match_condition, CONDITION_HOOK);
143 add_modification_hook(my_id, &set_modified);
144 add_hook(after_loop, STMT_HOOK_AFTER);
145 add_hook(&match_func_end, END_FUNC_HOOK);