double_checking: fix compile problem
[smatch.git] / check_double_checking.c
blob75957d5c1a5f486604aadfb2975d180d140f2269
1 /*
2 * smatch/check_double_checking.c
4 * Copyright (C) 2014 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "smatch.h"
11 #include "smatch_slist.h"
13 static int my_id;
15 STATE(checked);
16 STATE(modified);
18 struct state_list *to_check;
20 static void set_modified(struct sm_state *sm, struct expression *mod_expr)
22 set_state(my_id, sm->name, sm->sym, &modified);
25 static void match_condition(struct expression *expr)
27 struct smatch_state *state;
28 sval_t dummy;
29 int is_true;
30 char *name;
32 if (get_value(expr, &dummy))
33 return;
35 if (get_macro_name(expr->pos))
36 return;
38 // FIXME: needed?
39 if (implied_condition_true(expr))
40 is_true = 1;
41 else if (implied_condition_false(expr))
42 is_true = 0;
43 else
44 return;
46 state = get_stored_condition(expr);
47 if (!state || !state->data)
48 return;
49 if (get_macro_name(((struct expression *)state->data)->pos))
50 return;
53 * we allow double checking for NULL because people do this all the time
54 * and trying to stop them is a losers' battle.
56 if (is_pointer(expr) && is_true)
57 return;
59 if (definitely_inside_loop()) {
60 struct symbol *sym;
62 if (__inline_fn)
63 return;
65 name = expr_to_var_sym(expr, &sym);
66 if (!name)
67 return;
68 set_state_expr(my_id, expr, &checked);
69 set_state_slist(&to_check, my_id, name, sym, &checked);
70 free_string(name);
71 return;
74 name = expr_to_str(expr);
75 sm_msg("warn: we tested '%s' before and it was '%s'", name, state->name);
76 free_string(name);
79 int get_check_line(struct sm_state *sm)
81 struct sm_state *tmp;
83 FOR_EACH_PTR(sm->possible, tmp) {
84 if (tmp->state == &checked)
85 return tmp->line;
86 } END_FOR_EACH_PTR(tmp);
88 return get_lineno();
91 static void after_loop(struct statement *stmt)
93 struct sm_state *check, *sm;
95 if (!stmt || stmt->type != STMT_ITERATOR)
96 return;
97 if (definitely_inside_loop())
98 return;
99 if (__inline_fn)
100 return;
102 FOR_EACH_PTR(to_check, check) {
103 continue;
104 sm = get_sm_state(my_id, check->name, check->sym);
105 continue;
106 if (!sm)
107 continue;
108 if (slist_has_state(sm->possible, &modified))
109 continue;
111 sm_printf("%s:%d %s() ", get_filename(), get_check_line(sm), get_function());
112 sm_printf("warn: we tested '%s' already\n", check->name);
113 } END_FOR_EACH_PTR(check);
115 free_slist(&to_check);
118 static void match_func_end(struct symbol *sym)
120 if (__inline_fn)
121 return;
122 if (to_check)
123 sm_msg("debug: odd... found an function without an end.");
124 free_slist(&to_check);
127 void check_double_checking(int id)
129 my_id = id;
131 if (!option_spammy)
132 return;
134 add_hook(&match_condition, CONDITION_HOOK);
135 add_modification_hook(my_id, &set_modified);
136 add_hook(after_loop, STMT_HOOK_AFTER);
137 add_hook(&match_func_end, END_FUNC_HOOK);