1 /*
   2  * Copyright (C) 2010 Dan Carpenter.
   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  * There was a previous null dereference test but it was too confusing and
  20  * difficult to debug.  This test is much simpler in its goals and scope.
  21  *
  22  * This test only complains about:
  23  * 1) dereferencing uninitialized variables
  24  * 2) dereferencing variables which were assigned as null.
  25  * 3) dereferencing variables which were assigned a function the returns 
  26  *    null.
  27  *
  28  * If we dereference something then we complain if any of those three
  29  * are possible.
  30  *
  31  */
  32 
  33 #include "smatch.h"
  34 #include "smatch_slist.h"
  35 #include "smatch_extra.h"
  36 
  37 static int my_id;
  38 
  39 #define __GFP_NOFAIL 0x800
  40 
  41 STATE(null);
  42 STATE(ok);
  43 STATE(uninitialized);
  44 
  45 static struct smatch_state *alloc_my_state(const char *name)
  46 {
  47         struct smatch_state *state;
  48 
  49         state = __alloc_smatch_state(0);
  50         state->name = name;
  51         return state;
  52 }
  53 
  54 static struct smatch_state *unmatched_state(struct sm_state *sm)
  55 {
  56         return &ok;
  57 }
  58 
  59 static void is_ok(struct sm_state *sm, struct expression *mod_expr)
  60 {
  61         set_state(my_id, sm->name, sm->sym, &ok);
  62 }
  63 
  64 static void check_dereference(struct expression *expr)
  65 {
  66         struct sm_state *sm;
  67         struct sm_state *tmp;
  68 
  69         expr = strip_expr(expr);
  70         if (is_static(expr))
  71                 return;
  72         sm = get_sm_state_expr(my_id, expr);
  73         if (!sm)
  74                 return;
  75         if (is_ignored(my_id, sm->name, sm->sym))
  76                 return;
  77         if (implied_not_equal(expr, 0))
  78                 return;
  79         if (is_impossible_path())
  80                 return;
  81 
  82         FOR_EACH_PTR(sm->possible, tmp) {
  83                 if (tmp->state == &merged)
  84                         continue;
  85                 if (tmp->state == &ok)
  86                         continue;
  87                 add_ignore(my_id, sm->name, sm->sym);
  88                 if (tmp->state == &null) {
  89                         if (option_spammy)
  90                                 sm_error("potential NULL dereference '%s'.", tmp->name);
  91                         return;
  92                 }
  93                 if (tmp->state == &uninitialized) {
  94                         if (option_spammy)
  95                                 sm_error("potentially dereferencing uninitialized '%s'.", tmp->name);
  96                         return;
  97                 }
  98                 sm_error("potential null dereference '%s'.  (%s returns null)",
  99                         tmp->name, tmp->state->name);
 100                 return;
 101         } END_FOR_EACH_PTR(tmp);
 102 }
 103 
 104 static void check_dereference_name_sym(char *name, struct symbol *sym)
 105 {
 106         struct sm_state *sm;
 107         struct sm_state *tmp;
 108 
 109         sm = get_sm_state(my_id, name, sym);
 110         if (!sm)
 111                 return;
 112         if (is_ignored(my_id, sm->name, sm->sym))
 113                 return;
 114         if (implied_not_equal_name_sym(name, sym, 0))
 115                 return;
 116         if (is_impossible_path())
 117                 return;
 118 
 119         FOR_EACH_PTR(sm->possible, tmp) {
 120                 if (tmp->state == &merged)
 121                         continue;
 122                 if (tmp->state == &ok)
 123                         continue;
 124                 add_ignore(my_id, sm->name, sm->sym);
 125                 if (tmp->state == &null) {
 126                         if (option_spammy)
 127                                 sm_error("potential NULL dereference '%s'.", tmp->name);
 128                         return;
 129                 }
 130                 if (tmp->state == &uninitialized) {
 131                         if (option_spammy)
 132                                 sm_error("potentially dereferencing uninitialized '%s'.", tmp->name);
 133                         return;
 134                 }
 135                 sm_error("potential null dereference '%s'.  (%s returns null)",
 136                         tmp->name, tmp->state->name);
 137                 return;
 138         } END_FOR_EACH_PTR(tmp);
 139 }
 140 
 141 static void match_dereferences(struct expression *expr)
 142 {
 143         if (expr->type != EXPR_PREOP)
 144                 return;
 145         check_dereference(expr->unop);
 146 }
 147 
 148 static void match_pointer_as_array(struct expression *expr)
 149 {
 150         if (!is_array(expr))
 151                 return;
 152         check_dereference(get_array_base(expr));
 153 }
 154 
 155 static void set_param_dereferenced(struct expression *call, struct expression *arg, char *key, char *unused)
 156 {
 157         struct symbol *sym;
 158         char *name;
 159 
 160         name = get_variable_from_key(arg, key, &sym);
 161         if (!name || !sym)
 162                 goto free;
 163 
 164         check_dereference_name_sym(name, sym);
 165 free:
 166         free_string(name);
 167 }
 168 
 169 static void match_declarations(struct symbol *sym)
 170 {
 171         const char *name;
 172 
 173         if ((get_base_type(sym))->type == SYM_ARRAY)
 174                 return;
 175 
 176         if (!sym->ident)
 177                 return;
 178         name = sym->ident->name;
 179         if (!sym->initializer) {
 180                 set_state(my_id, name, sym, &uninitialized);
 181                 scoped_state(my_id, name, sym);
 182         }
 183 }
 184 
 185 static void match_assign(struct expression *expr)
 186 {
 187         struct statement *stmt;
 188 
 189         if (!is_zero(expr->right))
 190                 return;
 191 
 192         if (__in_fake_assign)
 193                 return;
 194 
 195         FOR_EACH_PTR_REVERSE(big_statement_stack, stmt) {
 196                 if (stmt->type == STMT_DECLARATION)
 197                         return;
 198                 break;
 199         } END_FOR_EACH_PTR_REVERSE(stmt);
 200 
 201         set_state_expr(my_id, expr->left, &null);
 202 }
 203 
 204 static void match_assigns_address(struct expression *expr)
 205 {
 206         struct expression *right;
 207 
 208         right = strip_expr(expr->right);
 209         if (right->type != EXPR_PREOP || right->op != '&')
 210                 return;
 211         set_state_expr(my_id, right, &ok);
 212 }
 213 
 214 static void match_condition(struct expression *expr)
 215 {
 216         if (expr->type == EXPR_ASSIGNMENT) {
 217                 match_condition(expr->right);
 218                 match_condition(expr->left);
 219         }
 220         if (!get_state_expr(my_id, expr))
 221                 return;
 222         set_true_false_states_expr(my_id, expr, &ok, NULL);
 223 }
 224 
 225 static int called_with_no_fail(struct expression *call, int param)
 226 {
 227         struct expression *arg;
 228         sval_t sval;
 229 
 230         if (param == -1)
 231                 return 0;
 232         call = strip_expr(call);
 233         if (call->type != EXPR_CALL)
 234                 return 0;
 235         arg = get_argument_from_call_expr(call->args, param);
 236         if (get_value(arg, &sval) && (sval.uvalue & __GFP_NOFAIL))
 237                 return 1;
 238         return 0;
 239 }
 240 
 241 static void match_assign_returns_null(const char *fn, struct expression *expr, void *_gfp)
 242 {
 243         struct smatch_state *state;
 244         int gfp_param = PTR_INT(_gfp);
 245 
 246         if (called_with_no_fail(expr->right, gfp_param))
 247                 return;
 248         state = alloc_my_state(fn);
 249         set_state_expr(my_id, expr->left, state);
 250 }
 251 
 252 static void register_allocation_funcs(void)
 253 {
 254         struct token *token;
 255         const char *func;
 256         int arg;
 257 
 258         token = get_tokens_file("kernel.allocation_funcs_gfp");
 259         if (!token)
 260                 return;
 261         if (token_type(token) != TOKEN_STREAMBEGIN)
 262                 return;
 263         token = token->next;
 264         while (token_type(token) != TOKEN_STREAMEND) {
 265                 if (token_type(token) != TOKEN_IDENT)
 266                         return;
 267                 func = show_ident(token->ident);
 268                 token = token->next;
 269                 if (token_type(token) == TOKEN_IDENT)
 270                         arg = -1;
 271                 else if (token_type(token) == TOKEN_NUMBER)
 272                         arg = atoi(token->number);
 273                 else
 274                         return;
 275                 add_function_assign_hook(func, &match_assign_returns_null, INT_PTR(arg));
 276                 token = token->next;
 277         }
 278         clear_token_alloc();
 279 }
 280 
 281 void check_deref(int id)
 282 {
 283         my_id = id;
 284 
 285         add_unmatched_state_hook(my_id, &unmatched_state);
 286         add_modification_hook(my_id, &is_ok);
 287         add_hook(&match_dereferences, DEREF_HOOK);
 288         add_hook(&match_pointer_as_array, OP_HOOK);
 289         select_return_implies_hook(DEREFERENCE, &set_param_dereferenced);
 290         add_hook(&match_condition, CONDITION_HOOK);
 291         add_hook(&match_declarations, DECLARATION_HOOK);
 292         add_hook(&match_assign, ASSIGNMENT_HOOK);
 293         add_hook(&match_assigns_address, ASSIGNMENT_HOOK);
 294         if (option_project == PROJ_KERNEL)
 295                 register_allocation_funcs();
 296 }