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 } 297