1*1f5207b7SJohn Levon /* 2*1f5207b7SJohn Levon * Copyright (C) 2010 Dan Carpenter. 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 * This is like check_deref_check.c except that it complains about code like: 20*1f5207b7SJohn Levon * if (a) 21*1f5207b7SJohn Levon * a->foo = 42; 22*1f5207b7SJohn Levon * a->bar = 7; 23*1f5207b7SJohn Levon * 24*1f5207b7SJohn Levon * Of course, Smatch has complained about these for forever but the problem is 25*1f5207b7SJohn Levon * the old scripts were too messy and complicated and generated too many false 26*1f5207b7SJohn Levon * positives. 27*1f5207b7SJohn Levon * 28*1f5207b7SJohn Levon * This check is supposed to be simpler because it only looks for one kind of 29*1f5207b7SJohn Levon * null dereference bug instead of every kind. It also gets rid of the false 30*1f5207b7SJohn Levon * positives caused by the checks that happen inside macros. 31*1f5207b7SJohn Levon * 32*1f5207b7SJohn Levon */ 33*1f5207b7SJohn Levon 34*1f5207b7SJohn Levon #include "smatch.h" 35*1f5207b7SJohn Levon #include "smatch_slist.h" 36*1f5207b7SJohn Levon #include "smatch_extra.h" 37*1f5207b7SJohn Levon 38*1f5207b7SJohn Levon static int my_id; 39*1f5207b7SJohn Levon 40*1f5207b7SJohn Levon STATE(null); 41*1f5207b7SJohn Levon STATE(ok); 42*1f5207b7SJohn Levon 43*1f5207b7SJohn Levon static void is_ok(struct sm_state *sm, struct expression *mod_expr) 44*1f5207b7SJohn Levon { 45*1f5207b7SJohn Levon set_state(my_id, sm->name, sm->sym, &ok); 46*1f5207b7SJohn Levon } 47*1f5207b7SJohn Levon 48*1f5207b7SJohn Levon static void check_dereference(struct expression *expr) 49*1f5207b7SJohn Levon { 50*1f5207b7SJohn Levon struct sm_state *sm; 51*1f5207b7SJohn Levon struct sm_state *tmp; 52*1f5207b7SJohn Levon 53*1f5207b7SJohn Levon if (__in_fake_assign) 54*1f5207b7SJohn Levon return; 55*1f5207b7SJohn Levon 56*1f5207b7SJohn Levon expr = strip_expr(expr); 57*1f5207b7SJohn Levon 58*1f5207b7SJohn Levon sm = get_sm_state_expr(my_id, expr); 59*1f5207b7SJohn Levon if (!sm) 60*1f5207b7SJohn Levon return; 61*1f5207b7SJohn Levon if (is_ignored(my_id, sm->name, sm->sym)) 62*1f5207b7SJohn Levon return; 63*1f5207b7SJohn Levon if (implied_not_equal(expr, 0)) 64*1f5207b7SJohn Levon return; 65*1f5207b7SJohn Levon 66*1f5207b7SJohn Levon FOR_EACH_PTR(sm->possible, tmp) { 67*1f5207b7SJohn Levon if (tmp->state == &merged) 68*1f5207b7SJohn Levon continue; 69*1f5207b7SJohn Levon if (tmp->state == &ok) 70*1f5207b7SJohn Levon continue; 71*1f5207b7SJohn Levon if (tmp->state == &null) { 72*1f5207b7SJohn Levon sm_error("we previously assumed '%s' could be null (see line %d)", 73*1f5207b7SJohn Levon tmp->name, tmp->line); 74*1f5207b7SJohn Levon add_ignore(my_id, sm->name, sm->sym); 75*1f5207b7SJohn Levon return; 76*1f5207b7SJohn Levon } 77*1f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 78*1f5207b7SJohn Levon } 79*1f5207b7SJohn Levon 80*1f5207b7SJohn Levon static void check_dereference_name_sym(char *name, struct symbol *sym) 81*1f5207b7SJohn Levon { 82*1f5207b7SJohn Levon struct sm_state *sm; 83*1f5207b7SJohn Levon struct sm_state *tmp; 84*1f5207b7SJohn Levon 85*1f5207b7SJohn Levon sm = get_sm_state(my_id, name, sym); 86*1f5207b7SJohn Levon if (!sm) 87*1f5207b7SJohn Levon return; 88*1f5207b7SJohn Levon if (is_ignored(my_id, sm->name, sm->sym)) 89*1f5207b7SJohn Levon return; 90*1f5207b7SJohn Levon if (implied_not_equal_name_sym(name, sym, 0)) 91*1f5207b7SJohn Levon return; 92*1f5207b7SJohn Levon 93*1f5207b7SJohn Levon FOR_EACH_PTR(sm->possible, tmp) { 94*1f5207b7SJohn Levon if (tmp->state == &merged) 95*1f5207b7SJohn Levon continue; 96*1f5207b7SJohn Levon if (tmp->state == &ok) 97*1f5207b7SJohn Levon continue; 98*1f5207b7SJohn Levon if (tmp->state == &null) { 99*1f5207b7SJohn Levon sm_error("we previously assumed '%s' could be null (see line %d)", 100*1f5207b7SJohn Levon tmp->name, tmp->line); 101*1f5207b7SJohn Levon add_ignore(my_id, sm->name, sm->sym); 102*1f5207b7SJohn Levon return; 103*1f5207b7SJohn Levon } 104*1f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 105*1f5207b7SJohn Levon } 106*1f5207b7SJohn Levon 107*1f5207b7SJohn Levon static void match_dereferences(struct expression *expr) 108*1f5207b7SJohn Levon { 109*1f5207b7SJohn Levon if (expr->type != EXPR_PREOP) 110*1f5207b7SJohn Levon return; 111*1f5207b7SJohn Levon check_dereference(expr->unop); 112*1f5207b7SJohn Levon } 113*1f5207b7SJohn Levon 114*1f5207b7SJohn Levon static void match_pointer_as_array(struct expression *expr) 115*1f5207b7SJohn Levon { 116*1f5207b7SJohn Levon if (!is_array(expr)) 117*1f5207b7SJohn Levon return; 118*1f5207b7SJohn Levon check_dereference(get_array_base(expr)); 119*1f5207b7SJohn Levon } 120*1f5207b7SJohn Levon 121*1f5207b7SJohn Levon static void set_param_dereferenced(struct expression *call, struct expression *arg, char *key, char *unused) 122*1f5207b7SJohn Levon { 123*1f5207b7SJohn Levon struct symbol *sym; 124*1f5207b7SJohn Levon char *name; 125*1f5207b7SJohn Levon 126*1f5207b7SJohn Levon name = get_variable_from_key(arg, key, &sym); 127*1f5207b7SJohn Levon if (!name || !sym) 128*1f5207b7SJohn Levon goto free; 129*1f5207b7SJohn Levon 130*1f5207b7SJohn Levon check_dereference_name_sym(name, sym); 131*1f5207b7SJohn Levon free: 132*1f5207b7SJohn Levon free_string(name); 133*1f5207b7SJohn Levon } 134*1f5207b7SJohn Levon 135*1f5207b7SJohn Levon static void match_condition(struct expression *expr) 136*1f5207b7SJohn Levon { 137*1f5207b7SJohn Levon struct smatch_state *true_state = NULL; 138*1f5207b7SJohn Levon 139*1f5207b7SJohn Levon if (get_macro_name(expr->pos)) 140*1f5207b7SJohn Levon return; 141*1f5207b7SJohn Levon 142*1f5207b7SJohn Levon if (!is_pointer(expr)) 143*1f5207b7SJohn Levon return; 144*1f5207b7SJohn Levon 145*1f5207b7SJohn Levon if (expr->type == EXPR_ASSIGNMENT) { 146*1f5207b7SJohn Levon match_condition(expr->right); 147*1f5207b7SJohn Levon match_condition(expr->left); 148*1f5207b7SJohn Levon } 149*1f5207b7SJohn Levon 150*1f5207b7SJohn Levon if (implied_not_equal(expr, 0)) 151*1f5207b7SJohn Levon return; 152*1f5207b7SJohn Levon 153*1f5207b7SJohn Levon if (get_state_expr(my_id, expr)) 154*1f5207b7SJohn Levon true_state = &ok; 155*1f5207b7SJohn Levon 156*1f5207b7SJohn Levon set_true_false_states_expr(my_id, expr, true_state, &null); 157*1f5207b7SJohn Levon } 158*1f5207b7SJohn Levon 159*1f5207b7SJohn Levon void check_check_deref(int id) 160*1f5207b7SJohn Levon { 161*1f5207b7SJohn Levon my_id = id; 162*1f5207b7SJohn Levon 163*1f5207b7SJohn Levon add_modification_hook(my_id, &is_ok); 164*1f5207b7SJohn Levon add_hook(&match_dereferences, DEREF_HOOK); 165*1f5207b7SJohn Levon add_hook(&match_pointer_as_array, OP_HOOK); 166*1f5207b7SJohn Levon select_return_implies_hook(DEREFERENCE, &set_param_dereferenced); 167*1f5207b7SJohn Levon add_hook(&match_condition, CONDITION_HOOK); 168*1f5207b7SJohn Levon } 169