mtag: delete uncalled remove_dereference() function
[smatch.git] / smatch_mtag.c
blob90b6aff7d246fbf80d3d96ff9210b6aaf36505ed
1 /*
2 * Copyright (C) 2017 Oracle. All rights reserved.
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
19 * One problem that I have is that it's really hard to track how pointers are
20 * passed around. For example, it would be nice to know that the probe() and
21 * remove() functions get the same pci_dev pointer. It would be good to know
22 * what pointers we're passing to the open() and close() functions. But that
23 * information gets lost in a call tree full of function pointer calls.
25 * I think the first step is to start naming specific pointers. So when a
26 * pointer is allocated, then it gets a tag. So calls to kmalloc() generate a
27 * tag. But we might not use that, because there might be a better name like
28 * framebuffer_alloc(). The framebuffer_alloc() is interesting because there is
29 * one per driver and it's passed around to all the file operations.
31 * Perhaps we could make a list of functions like framebuffer_alloc() which take
32 * a size and say that those are the interesting alloc functions.
34 * Another place where we would maybe name the pointer is when they are passed
35 * to the probe(). Because that's an important pointer, since there is one
36 * per driver (sort of).
38 * My vision is that you could take a pointer and trace it back to a global. So
39 * I'm going to track that pointer_tag - 28 bytes takes you to another pointer
40 * tag. You could follow that one back and so on. Also when we pass a pointer
41 * to a function that would be recorded as sort of a link or path or something.
45 #include "smatch.h"
46 #include "smatch_slist.h"
47 #include "smatch_extra.h"
49 #include <openssl/md5.h>
51 static int my_id;
53 static mtag_t str_to_tag(const char *str)
55 unsigned char c[MD5_DIGEST_LENGTH];
56 unsigned long long *tag = (unsigned long long *)&c;
57 MD5_CTX mdContext;
58 int len;
60 len = strlen(str);
61 MD5_Init(&mdContext);
62 MD5_Update(&mdContext, str, len);
63 MD5_Final(c, &mdContext);
65 *tag &= ~MTAG_ALIAS_BIT;
66 *tag &= ~MTAG_OFFSET_MASK;
68 return *tag;
71 const struct {
72 const char *name;
73 int size_arg;
74 } allocator_info[] = {
75 { "kmalloc", 0 },
76 { "kzalloc", 0 },
77 { "devm_kmalloc", 1},
78 { "devm_kzalloc", 1},
81 static bool is_mtag_call(struct expression *expr)
83 struct expression *arg;
84 int i;
85 sval_t sval;
87 if (expr->type != EXPR_CALL ||
88 expr->fn->type != EXPR_SYMBOL ||
89 !expr->fn->symbol)
90 return false;
92 for (i = 0; i < ARRAY_SIZE(allocator_info); i++) {
93 if (strcmp(expr->fn->symbol->ident->name, allocator_info[i].name) == 0)
94 break;
96 if (i == ARRAY_SIZE(allocator_info))
97 return false;
99 arg = get_argument_from_call_expr(expr->args, allocator_info[i].size_arg);
100 if (!get_implied_value(arg, &sval))
101 return false;
103 return true;
106 struct smatch_state *swap_mtag_return(struct expression *expr, struct smatch_state *state)
108 struct expression *left, *right;
109 char *left_name, *right_name;
110 struct symbol *left_sym;
111 struct range_list *rl;
112 char buf[256];
113 mtag_t tag;
114 sval_t tag_sval;
116 if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
117 return state;
119 if (!estate_rl(state) || strcmp(state->name, "0,4096-ptr_max") != 0)
120 return state;
122 left = strip_expr(expr->left);
123 right = strip_expr(expr->right);
125 if (!is_mtag_call(right))
126 return state;
128 left_name = expr_to_str_sym(left, &left_sym);
129 if (!left_name || !left_sym)
130 return state;
131 right_name = expr_to_str(right);
133 snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
134 left_name, right_name);
135 tag = str_to_tag(buf);
136 tag_sval.type = estate_type(state);
137 tag_sval.uvalue = tag;
139 rl = rl_filter(estate_rl(state), valid_ptr_rl);
140 rl = clone_rl(rl);
141 add_range(&rl, tag_sval, tag_sval);
143 sql_insert_mtag_about(tag, left_name, buf);
145 free_string(left_name);
146 free_string(right_name);
148 return alloc_estate_rl(rl);
151 int get_string_mtag(struct expression *expr, mtag_t *tag)
153 mtag_t xor;
155 if (expr->type != EXPR_STRING || !expr->string)
156 return 0;
158 /* I was worried about collisions so I added a xor */
159 xor = str_to_tag("__smatch string");
160 *tag = str_to_tag(expr->string->data);
161 *tag = *tag ^ xor;
163 return 1;
166 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag)
168 char buf[256];
170 if (!sym)
171 return 0;
173 if (!sym->ident ||
174 !(sym->ctype.modifiers & MOD_TOPLEVEL))
175 return 0;
177 snprintf(buf, sizeof(buf), "%s %s",
178 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern",
179 sym->ident->name);
180 *tag = str_to_tag(buf);
181 return 1;
184 int get_deref_mtag(struct expression *expr, mtag_t *tag)
186 mtag_t container_tag, member_tag;
187 int offset;
190 * I'm not totally sure what I'm doing...
192 * This is supposed to get something like "global_var->ptr", but I don't
193 * feel like it's complete at all.
197 if (!get_mtag(expr->unop, &container_tag))
198 return 0;
200 offset = get_member_offset_from_deref(expr);
201 if (offset < 0)
202 return 0;
204 if (!mtag_map_select_tag(container_tag, -offset, &member_tag))
205 return 0;
207 *tag = member_tag;
208 return 1;
211 static void global_variable(struct symbol *sym)
213 mtag_t tag;
215 if (!get_toplevel_mtag(sym, &tag))
216 return;
218 sql_insert_mtag_about(tag,
219 sym->ident->name,
220 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern");
223 static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
225 struct expression *array, *offset_expr;
226 struct symbol *type;
227 sval_t sval;
228 int start_offset;
230 if (!is_array(expr))
231 return 0;
233 array = get_array_base(expr);
234 if (!array)
235 return 0;
236 type = get_type(array);
237 if (!type || type->type != SYM_ARRAY)
238 return 0;
239 type = get_real_base_type(type);
240 if (!type_bytes(type))
241 return 0;
243 if (!expr_to_mtag_offset(array, tag, &start_offset))
244 return 0;
246 offset_expr = get_array_offset(expr);
247 if (!get_value(offset_expr, &sval))
248 return 0;
249 *offset = start_offset + sval.value * type_bytes(type);
251 return 1;
254 static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
256 struct smatch_state *state;
257 struct symbol *type;
258 sval_t sval;
260 type = get_type(expr);
261 if (!type_is_ptr(type))
262 return 0;
263 state = get_extra_state(expr);
264 if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
265 return 0;
267 *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
268 *offset = sval.uvalue & MTAG_OFFSET_MASK;
269 return 1;
272 static int get_mtag_cnt;
273 int get_mtag(struct expression *expr, mtag_t *tag)
275 int ret = 0;
277 expr = strip_expr(expr);
278 if (!expr)
279 return 0;
281 if (get_mtag_cnt > 0)
282 return 0;
284 get_mtag_cnt++;
286 switch (expr->type) {
287 case EXPR_STRING:
288 if (get_string_mtag(expr, tag)) {
289 ret = 1;
290 goto dec_cnt;
292 break;
293 case EXPR_SYMBOL:
294 if (get_toplevel_mtag(expr->symbol, tag)) {
295 ret = 1;
296 goto dec_cnt;
298 break;
299 case EXPR_DEREF:
300 if (get_deref_mtag(expr, tag)) {
301 ret = 1;
302 goto dec_cnt;
304 break;
307 dec_cnt:
308 get_mtag_cnt--;
309 return ret;
312 struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl)
314 char buf[256];
315 char *name;
316 sval_t sval;
317 mtag_t tag;
319 if (!rl_to_sval(rl, &sval))
320 return rl;
321 if (sval.type->type != SYM_PTR || sval.uvalue != MTAG_SEED)
322 return rl;
324 name = expr_to_str(expr);
325 snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name);
326 free_string(name);
327 tag = str_to_tag(buf);
328 sval.value = tag;
329 return alloc_rl(sval, sval);
332 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
334 char buf[256];
335 int lines_from_start;
336 char *str;
339 * We need the alias to be unique. It's not totally required that it
340 * be the same from one DB build to then next, but it makes debugging
341 * a bit simpler.
345 if (!cur_func_sym)
346 return 0;
348 lines_from_start = expr->pos.line - cur_func_sym->pos.line;
349 str = expr_to_str(expr);
350 snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str);
351 free_string(str);
353 *new = str_to_tag(buf);
354 sql_insert_mtag_alias(tag, *new);
356 return 1;
360 * The point of this function is to give you the mtag and the offset so
361 * you can look up the data in the DB. It takes an expression.
363 * So say you give it "foo->bar". Then it would give you the offset of "bar"
364 * and the implied value of "foo". Or if you lookup "*foo" then the offset is
365 * zero and we look up the implied value of "foo. But if the expression is
366 * foo, then if "foo" is a global variable, then we get the mtag and the offset
367 * is zero. If "foo" is a local variable, then there is nothing to look up in
368 * the mtag_data table because that's handled by smatch_extra.c to this returns
369 * false.
372 int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
374 *tag = 0;
375 *offset = 0;
377 expr = strip_expr(expr);
378 if (!expr)
379 return 0;
381 if (is_array(expr))
382 return get_array_mtag_offset(expr, tag, offset);
384 if (expr->type == EXPR_PREOP && expr->op == '*') {
385 expr = strip_expr(expr->unop);
386 if (get_implied_mtag_offset(expr, tag, offset))
387 return 1;
388 } else if (expr->type == EXPR_DEREF) {
389 int next_offset;
391 *offset = get_member_offset_from_deref(expr);
392 if (*offset < 0)
393 return 0;
394 expr = expr->deref;
395 if (expr->type == EXPR_PREOP && expr->op == '*')
396 expr = strip_expr(expr->unop);
398 if (get_implied_mtag_offset(expr, tag, &next_offset)) {
399 // FIXME: look it up recursively?
400 if (next_offset)
401 return 0;
402 return 1;
406 switch (expr->type) {
407 case EXPR_STRING:
408 return get_string_mtag(expr, tag);
409 case EXPR_SYMBOL:
410 return get_toplevel_mtag(expr->symbol, tag);
412 return 0;
415 int get_mtag_sval(struct expression *expr, sval_t *sval)
417 struct symbol *type;
418 mtag_t tag;
419 int offset = 0;
421 if (bits_in_pointer != 64)
422 return 0;
424 expr = strip_expr(expr);
426 type = get_type(expr);
427 if (!type_is_ptr(type))
428 return 0;
430 * There are only three options:
432 * 1) An array address:
433 * p = array;
434 * 2) An address like so:
435 * p = &my_struct->member;
436 * 3) A pointer:
437 * p = pointer;
441 if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag))
442 goto found;
444 if (expr->type == EXPR_SYMBOL &&
445 (type->type == SYM_ARRAY || type->type == SYM_FN) &&
446 get_toplevel_mtag(expr->symbol, &tag))
447 goto found;
449 if (get_implied_mtag_offset(expr, &tag, &offset))
450 goto found;
452 if (expr->type != EXPR_PREOP || expr->op != '&')
453 return 0;
454 expr = strip_expr(expr->unop);
456 if (!expr_to_mtag_offset(expr, &tag, &offset))
457 return 0;
458 if (offset > MTAG_OFFSET_MASK)
459 offset = MTAG_OFFSET_MASK;
461 found:
462 sval->type = type;
463 sval->uvalue = tag | offset;
465 return 1;
468 void register_mtag(int id)
470 my_id = id;
474 * The mtag stuff only works on 64 systems because we store the
475 * information in the pointer itself.
476 * bit 63 : set for alias mtags
477 * bit 62-12: mtag hash
478 * bit 11-0 : offset
481 if (bits_in_pointer != 64)
482 return;
484 add_hook(&global_variable, BASE_HOOK);