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 }