1 /* 2 * Copyright (C) 20XX Your Name. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt 16 */ 17 18 /* 19 * First of all, it's best if you lower your expectations from finding 20 * errors to just finding suspicious code. There tends to be a lot 21 * of false positives so having low expectations helps. 22 * 23 * For this test let's look for functions that return a negative value 24 * with a semaphore held. 25 * 26 * This is just a template check. It's designed for teaching 27 * only and is deliberately less useful than it could be. check_locking.c 28 * is a better real world test. 29 * 30 * The biggest short coming is that it assumes a function isn't supposed 31 * to return negative with a lock held. Also it assumes the function was 32 * called without the lock held. It would be better if it handled the stuff 33 * like this: 34 * ret = -ENOMEM; 35 * return ret; 36 * Another idea would be to test other kinds of locks besides just semaphores. 37 * 38 */ 39 40 #include "smatch.h" 41 #include "smatch_slist.h" 42 43 static int my_id; 44 45 STATE(lock); 46 STATE(unlock); 47 48 /* 49 * unmatched_state() deals with the case where code is known to be 50 * locked on one path but not known on the other side of a merge. Here 51 * we assume it's the opposite. 52 */ 53 54 static struct smatch_state *unmatched_state(struct sm_state *sm) 55 { 56 if (sm->state == &lock) 57 return &unlock; 58 if (sm->state == &unlock) 59 return &lock; 60 return &undefined; 61 } 62 63 static void match_call(struct expression *expr) 64 { 65 char *fn_name; 66 struct expression *sem_expr; 67 char *sem_name; 68 69 fn_name = expr_to_var(expr->fn); 70 if (!fn_name || (strcmp(fn_name, "down") && strcmp(fn_name, "up"))) 71 goto free_fn; 72 73 sem_expr = get_argument_from_call_expr(expr->args, 0); 74 sem_name = expr_to_var(sem_expr); 75 if (!strcmp(fn_name, "down")) { 76 set_state(my_id, sem_name, NULL, &lock); 77 } else { 78 set_state(my_id, sem_name, NULL, &unlock); 79 } 80 free_string(sem_name); 81 free_fn: 82 free_string(fn_name); 83 } 84 85 static void match_return(struct expression *ret_value) 86 { 87 sval_t ret_val; 88 struct stree *stree; 89 struct sm_state *tmp; 90 91 if (!get_value(ret_value, &ret_val) || sval_cmp_val(ret_val, 0) >= 0) 92 return; 93 94 stree = __get_cur_stree(); 95 FOR_EACH_MY_SM(my_id, stree, tmp) { 96 if (tmp->state != &unlock) 97 sm_warning("returned negative with %s semaphore held", 98 tmp->name); 99 } END_FOR_EACH_SM(tmp); 100 } 101 102 void check_template(int id) 103 { 104 my_id = id; 105 add_unmatched_state_hook(my_id, &unmatched_state); 106 add_hook(&match_call, FUNCTION_CALL_HOOK); 107 add_hook(&match_return, RETURN_HOOK); 108 }