Fix the Unclear locking thing. Again.
[smatch.git] / check_template.c
blob0db286782e2dbb839f9aa6ff045a87b14e299e50
1 /*
2 * sparse/check_template.c
4 * Copyright (C) 20XX Your Name.
6 * Licensed under the Open Software License version 1.1
8 */
11 * First of all, it's best if you lower your expectations from finding
12 * errors to just finding suspicious code. There tends to be a lot
13 * of false positives so having low expectations helps.
15 * For this test let's look for functions that return a negative value
16 * with a semaphore held.
18 * This is just a template check. It's designed for teaching
19 * only and is deliberately less useful than it could be.
21 * This test could be a lot better if it handled the stuff like this:
22 * ret = -ENOMEM;
23 * return ret;
24 * The correct way to handle that is to let smatch_extra store the
25 * value of ret. Then to use a *future* version of smatch that has
26 * the get_possible_states(name, SMATCH_EXTRA, sym) function. The
27 * possible states will be saved in merge_slist() in that future version.
29 * Another short coming is that it assumes a function isn't supposed
30 * to return negative with a lock held. Perhaps the function was
31 * called with the lock held. A more complicated script could check that.
33 * Also it would be more effective to check for other types of locks
34 * especially spinlocks.
38 #include "parse.h"
39 #include "smatch.h"
40 #include "smatch_slist.h" // blast this was supposed to be internal only stuff
42 static int my_id;
44 STATE(lock);
45 STATE(unlock);
48 * merge_func() can go away when we fix the core to just store all the possible
49 * states.
51 * The parameters are passed in alphabetical order with NULL at the beginning
52 * of the alphabet. (s2 is never NULL).
55 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
56 struct smatch_state *s1,
57 struct smatch_state *s2)
59 if (s1 == NULL)
60 return s2;
61 return &undefined;
65 static void match_call(struct expression *expr)
67 char *fn_name;
68 struct expression *sem_expr;
69 char *sem_name;
71 fn_name = get_variable_from_expr(expr->fn, NULL);
72 if (!fn_name || (strcmp(fn_name, "down") && strcmp(fn_name, "up")))
73 return;
75 sem_expr = get_argument_from_call_expr(expr->args, 0);
76 sem_name = get_variable_from_expr(sem_expr, NULL);
77 if (!strcmp(fn_name, "down")) {
78 set_state(sem_name, my_id, NULL, &lock);
79 } else {
80 set_state(sem_name, my_id, NULL, &unlock);
82 free_string(fn_name);
85 static void match_return(struct statement *stmt)
87 int ret_val;
88 struct state_list *slist;
89 struct sm_state *tmp;
91 ret_val = get_value(stmt->ret_value);
92 if (ret_val == UNDEFINED || ret_val >= 0)
93 return;
95 slist = get_all_states(my_id);
97 FOR_EACH_PTR(slist, tmp) {
98 if (tmp->state != &unlock)
99 smatch_msg("returned negative with %s semaphore held",
100 tmp->name);
101 } END_FOR_EACH_PTR(tmp);
104 void register_template(int id)
106 my_id = id;
107 add_merge_hook(my_id, &merge_func);
108 add_hook(&match_call, FUNCTION_CALL_HOOK);
109 add_hook(&match_return, RETURN_HOOK);