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