Print this page
11506 smatch resync
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/smatch_nul_terminator.c
+++ new/usr/src/tools/smatch/src/smatch_nul_terminator.c
1 1 /*
2 2 * Copyright (C) 2018 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 #include "smatch.h"
19 19 #include "smatch_slist.h"
20 20
21 21 static int my_id;
22 22 static int param_set_id;
23 23
24 24 STATE(terminated);
25 25 STATE(unterminated);
26 26 STATE(set);
27 27
28 28 static void set_terminated_var_sym(const char *name, struct symbol *sym, struct smatch_state *state)
29 29 {
30 30 if (get_param_num_from_sym(sym) >= 0)
31 31 set_state(param_set_id, name, sym, &set);
32 32 set_state(my_id, name, sym, state);
33 33 }
34 34
35 35 static void set_terminated(struct expression *expr, struct smatch_state *state)
36 36 {
37 37 struct symbol *sym;
38 38 char *name;
39 39
40 40 name = expr_to_var_sym(expr, &sym);
41 41 if (!name || !sym)
42 42 return;
43 43 set_terminated_var_sym(name, sym, state);
44 44 free_string(name);
45 45 }
46 46
47 47 static void match_nul_assign(struct expression *expr)
48 48 {
49 49 struct expression *array;
50 50 struct symbol *type;
51 51 sval_t sval;
52 52
53 53 if (expr->op != '=')
54 54 return;
55 55
56 56 if (!get_value(expr->right, &sval) || sval.value != 0)
57 57 return;
58 58
59 59 array = get_array_base(expr->left);
60 60 if (!array)
61 61 return;
62 62
63 63 type = get_type(array);
64 64 if (!type)
65 65 return;
66 66 type = get_real_base_type(type);
67 67 if (type != &char_ctype)
68 68 return;
69 69 set_terminated(array, &terminated);
70 70 }
71 71
72 72 static struct smatch_state *get_terminated_state(struct expression *expr)
73 73 {
74 74 struct sm_state *sm, *tmp;
75 75
76 76 if (!expr)
77 77 return NULL;
78 78 if (expr->type == EXPR_STRING)
79 79 return &terminated;
80 80 sm = get_sm_state_expr(my_id, expr);
81 81 if (!sm)
82 82 return NULL;
83 83 if (sm->state == &terminated || sm->state == &unterminated)
84 84 return sm->state;
85 85
86 86 FOR_EACH_PTR(sm->possible, tmp) {
87 87 if (tmp->state == &unterminated)
88 88 return &unterminated;
89 89 } END_FOR_EACH_PTR(tmp);
90 90
91 91 return NULL;
92 92 }
93 93
94 94 static void match_string_assign(struct expression *expr)
95 95 {
96 96 struct smatch_state *state;
97 97
98 98 if (expr->op != '=')
99 99 return;
100 100 state = get_terminated_state(expr->right);
101 101 if (!state)
102 102 return;
103 103 set_terminated(expr->left, state);
104 104 }
105 105
106 106 static int sm_to_term(struct sm_state *sm)
107 107 {
108 108 struct sm_state *tmp;
109 109
110 110 if (!sm)
111 111 return -1;
112 112 if (sm->state == &terminated)
113 113 return 1;
114 114
115 115 FOR_EACH_PTR(sm->possible, tmp) {
116 116 if (tmp->state == &unterminated)
117 117 return 0;
118 118 } END_FOR_EACH_PTR(tmp);
119 119
120 120 return -1;
121 121 }
122 122
123 123 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
124 124 {
125 125 int term;
126 126
127 127 term = sm_to_term(sm);
128 128 if (term < 0)
129 129 return;
130 130
131 131 sql_insert_caller_info(call, TERMINATED, param, printed_name, term ? "1" : "0");
132 132 }
133 133
134 134 static void match_call_info(struct expression *expr)
135 135 {
136 136 struct smatch_state *state;
137 137 struct expression *arg;
138 138 int i;
139 139
140 140 i = -1;
141 141 FOR_EACH_PTR(expr->args, arg) {
142 142 i++;
143 143
144 144 state = get_terminated_state(arg);
145 145 if (!state)
146 146 continue;
147 147 sql_insert_caller_info(expr, TERMINATED, i, "$",
148 148 (state == &terminated) ? "1" : "0");
149 149 } END_FOR_EACH_PTR(arg);
150 150 }
151 151
152 152 static void caller_info_terminated(const char *name, struct symbol *sym, char *key, char *value)
153 153 {
154 154 char fullname[256];
155 155
156 156 if (strcmp(key, "*$") == 0)
157 157 snprintf(fullname, sizeof(fullname), "*%s", name);
158 158 else if (strncmp(key, "$", 1) == 0)
159 159 snprintf(fullname, 256, "%s%s", name, key + 1);
160 160 else
161 161 return;
162 162
163 163 set_state(my_id, fullname, sym, (*value == '1') ? &terminated : &unterminated);
164 164 }
165 165
166 166 static void split_return_info(int return_id, char *return_ranges, struct expression *expr)
167 167 {
168 168 struct symbol *returned_sym;
169 169 struct sm_state *tmp, *sm;
170 170 const char *param_name;
171 171 int param;
172 172 int term;
173 173
174 174 FOR_EACH_MY_SM(param_set_id, __get_cur_stree(), tmp) {
175 175 sm = get_sm_state(my_id, tmp->name, tmp->sym);
176 176 if (!sm)
177 177 continue;
178 178 term = sm_to_term(sm);
179 179 if (term < 0)
180 180 continue;
181 181 param = get_param_num_from_sym(tmp->sym);
182 182 if (param < 0)
183 183 continue;
184 184
185 185 param_name = get_param_name(sm);
186 186 if (!param_name)
187 187 continue;
188 188 if (strcmp(param_name, "$") == 0)
189 189 continue;
190 190
191 191 sql_insert_return_states(return_id, return_ranges, TERMINATED,
192 192 param, param_name, term ? "1" : "0");
193 193 } END_FOR_EACH_SM(tmp);
194 194
195 195 returned_sym = expr_to_sym(expr);
196 196 if (!returned_sym)
197 197 return;
198 198
199 199 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
200 200 if (sm->sym != returned_sym)
201 201 continue;
202 202 term = sm_to_term(sm);
203 203 if (term < 0)
204 204 continue;
205 205 param_name = get_param_name(sm);
206 206 if (!param_name)
207 207 continue;
208 208 sql_insert_return_states(return_id, return_ranges, TERMINATED,
209 209 -1, param_name, term ? "1" : "0");
210 210 } END_FOR_EACH_SM(sm);
211 211 }
212 212
213 213 static void return_info_terminated(struct expression *expr, int param, char *key, char *value)
214 214 {
215 215 struct expression *arg;
216 216 char *name;
217 217 struct symbol *sym;
218 218
219 219 if (param == -1) {
220 220 arg = expr->left;
221 221 } else {
222 222 struct expression *call = expr;
223 223
224 224 while (call->type == EXPR_ASSIGNMENT)
225 225 call = strip_expr(call->right);
226 226 if (call->type != EXPR_CALL)
227 227 return;
228 228
229 229 arg = get_argument_from_call_expr(call->args, param);
230 230 if (!arg)
231 231 return;
232 232 }
233 233
234 234 name = get_variable_from_key(arg, key, &sym);
235 235 if (!name || !sym)
236 236 goto free;
237 237
238 238 set_terminated_var_sym(name, sym, (*value == '1') ? &terminated : &unterminated);
239 239 free:
↓ open down ↓ |
239 lines elided |
↑ open up ↑ |
240 240 free_string(name);
241 241 }
242 242
243 243 bool is_nul_terminated(struct expression *expr)
244 244 {
245 245 if (get_terminated_state(expr) == &terminated)
246 246 return 1;
247 247 return 0;
248 248 }
249 249
250 +static void match_strnlen_test(struct expression *expr)
251 +{
252 + struct expression *left, *tmp, *arg;
253 + int cnt;
254 +
255 + if (expr->type != EXPR_COMPARE)
256 + return;
257 + if (expr->op != SPECIAL_EQUAL && expr->op != SPECIAL_NOTEQUAL)
258 + return;
259 +
260 + left = strip_expr(expr->left);
261 + cnt = 0;
262 + while ((tmp = get_assigned_expr(left))) {
263 + if (cnt++ > 3)
264 + break;
265 + left = tmp;
266 + }
267 +
268 + if (left->type != EXPR_CALL)
269 + return;
270 + if (!sym_name_is("strnlen", left->fn))
271 + return;
272 + arg = get_argument_from_call_expr(left->args, 0);
273 + set_true_false_states_expr(my_id, arg,
274 + (expr->op == SPECIAL_EQUAL) ? &terminated : NULL,
275 + (expr->op == SPECIAL_NOTEQUAL) ? &terminated : NULL);
276 + if (get_param_num(arg) >= 0)
277 + set_true_false_states_expr(param_set_id, arg,
278 + (expr->op == SPECIAL_EQUAL) ? &terminated : NULL,
279 + (expr->op == SPECIAL_NOTEQUAL) ? &terminated : NULL);
280 +}
281 +
250 282 void register_nul_terminator(int id)
251 283 {
252 284 my_id = id;
253 285
254 286 add_hook(&match_nul_assign, ASSIGNMENT_HOOK);
255 287 add_hook(&match_string_assign, ASSIGNMENT_HOOK);
256 288
257 289 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
258 290 add_member_info_callback(my_id, struct_member_callback);
259 291 add_split_return_callback(&split_return_info);
260 292
261 293 select_caller_info_hook(caller_info_terminated, TERMINATED);
262 294 select_return_states_hook(TERMINATED, return_info_terminated);
295 +
296 + add_hook(&match_strnlen_test, CONDITION_HOOK);
263 297 }
264 298
265 299 void register_nul_terminator_param_set(int id)
266 300 {
267 301 param_set_id = id;
268 302 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX