Print this page
11506 smatch resync
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_missing_break.c
+++ new/usr/src/tools/smatch/src/check_missing_break.c
1 1 /*
2 2 * Copyright (C) 2013 Oracle.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 /*
19 19 * The way I'm detecting missing breaks is if there is an assignment inside a
20 20 * switch statement which is over written.
21 21 *
22 22 */
23 23
24 24 #include "smatch.h"
25 25 #include "smatch_slist.h"
26 26
27 27 static int my_id;
28 28 static struct expression *skip_this;
29 29
30 30 /*
31 31 * It goes like this:
32 32 * - Allocate a state which stores the switch expression. I wanted to
33 33 * just have a state &assigned but we need to know the switch statement where
34 34 * it was assigned.
35 35 * - If it gets used then we change it to &used.
36 36 * - For unmatched states we use &used (because of cleanness, not because we need
37 37 * to).
38 38 * - If we merge inside a case statement and one of the states is &assigned (or
39 39 * if it is &nobreak) then &nobreak is used.
40 40 *
41 41 * We print an error when we assign something to a &no_break symbol.
42 42 *
43 43 */
44 44
45 45 STATE(used);
46 46 STATE(no_break);
47 47
48 48 static int in_switch_stmt;
49 49
50 50 static struct smatch_state *alloc_my_state(struct expression *expr)
51 51 {
52 52 struct smatch_state *state;
53 53 char *name;
54 54
55 55 state = __alloc_smatch_state(0);
56 56 expr = strip_expr(expr);
57 57 name = expr_to_str(expr);
58 58 if (!name)
59 59 name = alloc_string("");
60 60 state->name = alloc_sname(name);
61 61 free_string(name);
62 62 state->data = expr;
63 63 return state;
64 64 }
65 65
66 66 struct expression *last_print_expr;
67 67 static void print_missing_break(struct expression *expr)
68 68 {
69 69 char *name;
70 70
71 71 if (get_switch_expr() == last_print_expr)
72 72 return;
73 73 last_print_expr = get_switch_expr();
74 74
75 75 name = expr_to_var(expr);
76 76 sm_warning("missing break? reassigning '%s'", name);
77 77 free_string(name);
78 78 }
79 79
80 80 static void match_assign(struct expression *expr)
81 81 {
82 82 struct expression *left;
83 83
84 84 if (expr->op != '=')
85 85 return;
86 86 if (!get_switch_expr())
87 87 return;
88 88 left = strip_expr(expr->left);
89 89 if (get_state_expr(my_id, left) == &no_break)
90 90 print_missing_break(left);
91 91
92 92 set_state_expr(my_id, left, alloc_my_state(get_switch_expr()));
93 93 skip_this = left;
94 94 }
95 95
96 96 static void match_symbol(struct expression *expr)
97 97 {
98 98 if (outside_of_function())
99 99 return;
100 100 if (!get_switch_expr())
101 101 return;
102 102
103 103 expr = strip_expr(expr);
104 104 if (expr == skip_this)
105 105 return;
106 106 set_state_expr(my_id, expr, &used);
107 107 }
108 108
109 109 static struct smatch_state *unmatched_state(struct sm_state *sm)
110 110 {
111 111 return &used;
112 112 }
113 113
114 114 static int in_case;
115 115 static struct smatch_state *merge_hook(struct smatch_state *s1, struct smatch_state *s2)
116 116 {
117 117 struct expression *switch_expr;
118 118
119 119 if (s1 == &no_break || s2 == &no_break)
120 120 return &no_break;
121 121 if (!in_case)
122 122 return &used;
123 123 switch_expr = get_switch_expr();
124 124 if (s1->data == switch_expr || s2->data == switch_expr)
125 125 return &no_break;
126 126 return &used;
127 127 }
128 128
129 129 static void match_stmt(struct statement *stmt)
130 130 {
131 131 if (stmt->type == STMT_CASE)
132 132 in_case = 1;
133 133 else
134 134 in_case = 0;
135 135 }
136 136
137 137 static void match_switch(struct statement *stmt)
138 138 {
139 139 if (stmt->type != STMT_SWITCH)
140 140 return;
141 141
142 142 in_switch_stmt++;
143 143 }
144 144
145 145 static void delete_my_states(int owner)
146 146 {
147 147 struct state_list *slist = NULL;
148 148 struct sm_state *sm;
149 149
150 150 FOR_EACH_MY_SM(owner, __get_cur_stree(), sm) {
151 151 add_ptr_list(&slist, sm);
152 152 } END_FOR_EACH_SM(sm);
153 153
154 154 FOR_EACH_PTR(slist, sm) {
155 155 delete_state(sm->owner, sm->name, sm->sym);
156 156 } END_FOR_EACH_PTR(sm);
157 157
158 158 free_slist(&slist);
159 159 }
160 160
161 161 static void match_switch_end(struct statement *stmt)
162 162 {
163 163
164 164 if (stmt->type != STMT_SWITCH)
165 165 return;
166 166
167 167 in_switch_stmt--;
168 168
169 169 if (!in_switch_stmt)
↓ open down ↓ |
169 lines elided |
↑ open up ↑ |
170 170 delete_my_states(my_id);
171 171 }
172 172
173 173 void check_missing_break(int id)
174 174 {
175 175 my_id = id;
176 176
177 177 if (!option_spammy)
178 178 return;
179 179
180 + set_dynamic_states(my_id);
180 181 add_unmatched_state_hook(my_id, &unmatched_state);
181 182 add_merge_hook(my_id, &merge_hook);
182 183
183 184 add_hook(&match_assign, ASSIGNMENT_HOOK);
184 185 add_hook(&match_symbol, SYM_HOOK);
185 186 add_hook(&match_stmt, STMT_HOOK);
186 187 add_hook(&match_switch, STMT_HOOK);
187 188 add_hook(&match_switch_end, STMT_HOOK_AFTER);
188 189 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX