sval: update smatch_helper.c
[smatch.git] / check_free.c
blob6e23cac848240472860c4f2c85f7d4d7090c531f
1 /*
2 * sparse/check_free.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * check_memory() is getting too big and messy.
15 #include "smatch.h"
16 #include "smatch_slist.h"
18 static int my_id;
20 STATE(freed);
21 STATE(ok);
23 static void ok_to_use(struct sm_state *sm)
25 if (sm->state != &ok)
26 set_state(my_id, sm->name, sm->sym, &ok);
29 static int is_freed(struct expression *expr)
31 struct sm_state *sm;
33 sm = get_sm_state_expr(my_id, expr);
34 if (sm && slist_has_state(sm->possible, &freed))
35 return 1;
36 return 0;
39 static void match_symbol(struct expression *expr)
41 char *name;
43 if (!is_freed(expr))
44 return;
45 name = get_variable_from_expr(expr, NULL);
46 sm_msg("warn: '%s' was already freed.", name);
47 free_string(name);
50 static void match_dereferences(struct expression *expr)
52 char *name;
54 if (expr->type != EXPR_PREOP)
55 return;
56 expr = strip_expr(expr->unop);
58 if (!is_freed(expr))
59 return;
60 name = get_variable_from_expr(expr, NULL);
61 sm_msg("error: dereferencing freed memory '%s'", name);
62 set_state_expr(my_id, expr, &ok);
63 free_string(name);
66 static void match_free(const char *fn, struct expression *expr, void *param)
68 struct expression *arg;
70 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
71 if (!arg)
72 return;
73 /* option_spammy already prints a warning here */
74 if (!option_spammy && is_freed(arg)) {
75 char *name = get_variable_from_expr(arg, NULL);
77 sm_msg("error: double free of '%s'", name);
78 free_string(name);
80 set_state_expr(my_id, arg, &freed);
83 void check_free(int id)
85 my_id = id;
87 if (option_project == PROJ_KERNEL)
88 add_function_hook("kfree", &match_free, (void *)0);
89 else
90 add_function_hook("free", &match_free, (void *)0);
92 if (option_spammy)
93 add_hook(&match_symbol, SYM_HOOK);
94 else
95 add_hook(&match_dereferences, DEREF_HOOK);
97 add_modification_hook(my_id, &ok_to_use);