fix crashing bug.
[smatch.git] / check_template.c
blobdc17476ce3be80fd25cc4c9b356f1094f353c275
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(my_id, sem_name, NULL, &lock);
69 } else {
70 set_state(my_id, sem_name, NULL, &unlock);
72 free_string(sem_name);
73 free_fn:
74 free_string(fn_name);
77 static void match_return(struct expression *ret_value)
79 long long ret_val;
80 struct state_list *slist;
81 struct sm_state *tmp;
83 if (!get_value(ret_value, &ret_val) || ret_val >= 0)
84 return;
86 slist = get_all_states(my_id);
87 FOR_EACH_PTR(slist, tmp) {
88 if (tmp->state != &unlock)
89 sm_msg("warn: returned negative with %s semaphore held",
90 tmp->name);
91 } END_FOR_EACH_PTR(tmp);
92 free_slist(&slist);
95 void check_template(int id)
97 my_id = id;
98 add_unmatched_state_hook(my_id, &unmatched_state);
99 add_hook(&match_call, FUNCTION_CALL_HOOK);
100 add_hook(&match_return, RETURN_HOOK);