__module_put_and_exit() doesn't return.
[smatch.git] / check_template.c
blob2f212f3b93e82083d38be89ae8a1abe4140e5087
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. check_locking.c
20 * is a better real world test.
22 * The biggest short coming is that it assumes a function isn't supposed
23 * to return negative with a lock held. Also it assumes the function was
24 * called without the lock held. It would be better if it handled the stuff
25 * like this:
26 * ret = -ENOMEM;
27 * return ret;
28 * Another idea would be to test other kinds of locks besides just semaphores.
32 #include "smatch.h"
33 #include "smatch_slist.h" // blast this was supposed to be internal only stuff
35 static int my_id;
37 STATE(lock);
38 STATE(unlock);
41 * unmatched_state() deals with the case where code is known to be
42 * locked on one path but not known on the other side of a merge. Here
43 * we assume it's the opposite.
46 static struct smatch_state *unmatched_state(struct sm_state *sm)
48 if (sm->state == &lock)
49 return &unlock;
50 if (sm->state == &unlock)
51 return &lock;
52 return &undefined;
55 static void match_call(struct expression *expr)
57 char *fn_name;
58 struct expression *sem_expr;
59 char *sem_name;
61 fn_name = get_variable_from_expr(expr->fn, NULL);
62 if (!fn_name || (strcmp(fn_name, "down") && strcmp(fn_name, "up")))
63 goto free_fn;
65 sem_expr = get_argument_from_call_expr(expr->args, 0);
66 sem_name = get_variable_from_expr(sem_expr, NULL);
67 if (!strcmp(fn_name, "down")) {
68 set_state(sem_name, my_id, NULL, &lock);
69 } else {
70 set_state(sem_name, my_id, NULL, &unlock);
72 free_string(sem_name);
73 free_fn:
74 free_string(fn_name);
77 static void match_return(struct statement *stmt)
79 int ret_val;
80 struct state_list *slist;
81 struct sm_state *tmp;
83 ret_val = get_value(stmt->ret_value);
84 if (ret_val == UNDEFINED || ret_val >= 0)
85 return;
87 slist = get_all_states(my_id);
88 FOR_EACH_PTR(slist, tmp) {
89 if (tmp->state != &unlock)
90 smatch_msg("warn: returned negative with %s semaphore held",
91 tmp->name);
92 } END_FOR_EACH_PTR(tmp);
93 free_slist(&slist);
96 void check_template(int id)
98 my_id = id;
99 add_unmatched_state_hook(my_id, &unmatched_state);
100 add_hook(&match_call, FUNCTION_CALL_HOOK);
101 add_hook(&match_return, RETURN_HOOK);