smatch.h: include scope.h
[smatch.git] / check_double_checking.c
blobdbf4a53f4ea1cf3958ea79ed871f0df6961a67e4
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 (__in_pre_post_condition)
33 return;
35 if (get_value(expr, &dummy))
36 return;
38 if (get_macro_name(expr->pos))
39 return;
41 // FIXME: needed?
42 if (implied_condition_true(expr))
43 is_true = 1;
44 else if (implied_condition_false(expr))
45 is_true = 0;
46 else
47 return;
49 state = get_stored_condition(expr);
50 if (!state || !state->data)
51 return;
52 if (get_macro_name(((struct expression *)state->data)->pos))
53 return;
56 * we allow double checking for NULL because people do this all the time
57 * and trying to stop them is a losers' battle.
59 if (is_pointer(expr) && is_true)
60 return;
62 if (definitely_inside_loop()) {
63 struct symbol *sym;
65 if (__inline_fn)
66 return;
68 name = expr_to_var_sym(expr, &sym);
69 if (!name)
70 return;
71 set_state_expr(my_id, expr, &checked);
72 set_state_slist(&to_check, my_id, name, sym, &checked);
73 free_string(name);
74 return;
77 name = expr_to_str(expr);
78 sm_msg("warn: we tested '%s' before and it was '%s'", name, state->name);
79 free_string(name);
82 int get_check_line(struct sm_state *sm)
84 struct sm_state *tmp;
86 FOR_EACH_PTR(sm->possible, tmp) {
87 if (tmp->state == &checked)
88 return tmp->line;
89 } END_FOR_EACH_PTR(tmp);
91 return get_lineno();
94 static void after_loop(struct statement *stmt)
96 struct sm_state *check, *sm;
98 if (!stmt || stmt->type != STMT_ITERATOR)
99 return;
100 if (definitely_inside_loop())
101 return;
102 if (__inline_fn)
103 return;
105 FOR_EACH_PTR(to_check, check) {
106 continue;
107 sm = get_sm_state(my_id, check->name, check->sym);
108 continue;
109 if (!sm)
110 continue;
111 if (slist_has_state(sm->possible, &modified))
112 continue;
114 sm_printf("%s:%d %s() ", get_filename(), get_check_line(sm), get_function());
115 sm_printf("warn: we tested '%s' already\n", check->name);
116 } END_FOR_EACH_PTR(check);
118 free_slist(&to_check);
121 static void match_func_end(struct symbol *sym)
123 if (__inline_fn)
124 return;
125 if (to_check)
126 sm_msg("debug: odd... found an function without an end.");
127 free_slist(&to_check);
130 void check_double_checking(int id)
132 my_id = id;
134 if (!option_spammy)
135 return;
137 add_hook(&match_condition, CONDITION_HOOK);
138 add_modification_hook(my_id, &set_modified);
139 add_hook(after_loop, STMT_HOOK_AFTER);
140 add_hook(&match_func_end, END_FUNC_HOOK);