Add a new function slist_has_state()
[smatch.git] / check_locking.c
blob506880e8b9f676629ab9efdd4aaabfb92ac1f605
1 /*
2 * sparse/check_locking.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * For this test let's look for functions that return a negative value
12 * with a spinlock held.
14 * One short coming is that it assumes a function isn't supposed
15 * to return negative with a lock held. Perhaps the function was
16 * called with the lock held. A more complicated script could check that.
20 #include "parse.h"
21 #include "smatch.h"
22 #include "smatch_slist.h" // blast this was supposed to be internal only stuff
24 static int my_id;
26 STATE(lock);
27 STATE(unlock);
30 * merge_func() can go away when we fix the core to just store all the possible
31 * states.
33 * The parameters are passed in alphabetical order with NULL at the beginning
34 * of the alphabet. (s2 is never NULL).
37 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
38 struct smatch_state *s1,
39 struct smatch_state *s2)
41 if (s1 == NULL)
42 return s2;
43 return &undefined;
47 static void match_call(struct expression *expr)
49 char *fn_name;
50 struct expression *spin_expr;
51 char *spin_name;
53 fn_name = get_variable_from_expr(expr->fn, NULL);
54 if (!fn_name || (strcmp(fn_name, "_spin_lock") && strcmp(fn_name, "_spin_unlock")))
55 return;
57 spin_expr = get_argument_from_call_expr(expr->args, 0);
58 spin_name = get_variable_from_expr(spin_expr, NULL);
59 if (!strcmp(fn_name, "_spin_lock")) {
60 set_state(spin_name, my_id, NULL, &lock);
61 } else {
62 set_state(spin_name, my_id, NULL, &unlock);
64 free_string(fn_name);
67 static void match_condition(struct expression *expr)
69 /* __raw_spin_is_locked */
72 static int possibly_negative(struct expression *expr)
74 char *name;
75 struct symbol *sym;
76 struct state_list *slist;
77 struct sm_state *tmp;
79 name = get_variable_from_expr(expr, &sym);
80 if (!name || !sym)
81 return 0;
82 slist = get_possible_states(name, SMATCH_EXTRA, sym);
83 FOR_EACH_PTR(slist, tmp) {
84 int value = 0;
86 if (tmp->state->data)
87 value = *(int *)tmp->state->data;
89 if (value < 0) {
90 return 1;
93 } END_FOR_EACH_PTR(tmp);
94 return 0;
97 static void match_return(struct statement *stmt)
99 int ret_val;
100 struct state_list *slist;
101 struct sm_state *tmp;
103 ret_val = get_value(stmt->ret_value);
104 if (ret_val >= 0) {
105 return;
107 if (ret_val == UNDEFINED) {
108 if (!possibly_negative(stmt->ret_value))
109 return;
112 slist = get_all_states(my_id);
113 FOR_EACH_PTR(slist, tmp) {
114 if (tmp->state != &unlock)
115 smatch_msg("returned negative with %s spinlock held",
116 tmp->name);
117 } END_FOR_EACH_PTR(tmp);
120 void register_locking(int id)
122 my_id = id;
123 add_merge_hook(my_id, &merge_func);
124 add_hook(&match_call, FUNCTION_CALL_HOOK);
125 add_hook(&match_return, RETURN_HOOK);