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 * smatch_equiv.c is for tracking how variables are the same 20*1f5207b7SJohn Levon * 21*1f5207b7SJohn Levon * if (a == b) { 22*1f5207b7SJohn Levon * Or 23*1f5207b7SJohn Levon * x = y; 24*1f5207b7SJohn Levon * 25*1f5207b7SJohn Levon * When a variable gets modified all the old relationships are 26*1f5207b7SJohn Levon * deleted. remove_equiv(expr); 27*1f5207b7SJohn Levon * 28*1f5207b7SJohn Levon */ 29*1f5207b7SJohn Levon 30*1f5207b7SJohn Levon #include "smatch.h" 31*1f5207b7SJohn Levon #include "smatch_slist.h" 32*1f5207b7SJohn Levon #include "smatch_extra.h" 33*1f5207b7SJohn Levon 34*1f5207b7SJohn Levon ALLOCATOR(relation, "related variables"); 35*1f5207b7SJohn Levon 36*1f5207b7SJohn Levon static struct relation *alloc_relation(const char *name, struct symbol *sym) 37*1f5207b7SJohn Levon { 38*1f5207b7SJohn Levon struct relation *tmp; 39*1f5207b7SJohn Levon 40*1f5207b7SJohn Levon tmp = __alloc_relation(0); 41*1f5207b7SJohn Levon tmp->name = alloc_string(name); 42*1f5207b7SJohn Levon tmp->sym = sym; 43*1f5207b7SJohn Levon return tmp; 44*1f5207b7SJohn Levon } 45*1f5207b7SJohn Levon 46*1f5207b7SJohn Levon struct related_list *clone_related_list(struct related_list *related) 47*1f5207b7SJohn Levon { 48*1f5207b7SJohn Levon struct relation *rel; 49*1f5207b7SJohn Levon struct related_list *to_list = NULL; 50*1f5207b7SJohn Levon 51*1f5207b7SJohn Levon FOR_EACH_PTR(related, rel) { 52*1f5207b7SJohn Levon add_ptr_list(&to_list, rel); 53*1f5207b7SJohn Levon } END_FOR_EACH_PTR(rel); 54*1f5207b7SJohn Levon 55*1f5207b7SJohn Levon return to_list; 56*1f5207b7SJohn Levon } 57*1f5207b7SJohn Levon 58*1f5207b7SJohn Levon static int cmp_relation(struct relation *a, struct relation *b) 59*1f5207b7SJohn Levon { 60*1f5207b7SJohn Levon int ret; 61*1f5207b7SJohn Levon 62*1f5207b7SJohn Levon if (a == b) 63*1f5207b7SJohn Levon return 0; 64*1f5207b7SJohn Levon 65*1f5207b7SJohn Levon if (a->sym > b->sym) 66*1f5207b7SJohn Levon return -1; 67*1f5207b7SJohn Levon if (a->sym < b->sym) 68*1f5207b7SJohn Levon return 1; 69*1f5207b7SJohn Levon 70*1f5207b7SJohn Levon ret = strcmp(a->name, b->name); 71*1f5207b7SJohn Levon if (ret) 72*1f5207b7SJohn Levon return ret; 73*1f5207b7SJohn Levon 74*1f5207b7SJohn Levon return 0; 75*1f5207b7SJohn Levon } 76*1f5207b7SJohn Levon 77*1f5207b7SJohn Levon struct related_list *get_shared_relations(struct related_list *one, 78*1f5207b7SJohn Levon struct related_list *two) 79*1f5207b7SJohn Levon { 80*1f5207b7SJohn Levon struct related_list *ret = NULL; 81*1f5207b7SJohn Levon struct relation *one_rel; 82*1f5207b7SJohn Levon struct relation *two_rel; 83*1f5207b7SJohn Levon 84*1f5207b7SJohn Levon PREPARE_PTR_LIST(one, one_rel); 85*1f5207b7SJohn Levon PREPARE_PTR_LIST(two, two_rel); 86*1f5207b7SJohn Levon for (;;) { 87*1f5207b7SJohn Levon if (!one_rel || !two_rel) 88*1f5207b7SJohn Levon break; 89*1f5207b7SJohn Levon if (cmp_relation(one_rel, two_rel) < 0) { 90*1f5207b7SJohn Levon NEXT_PTR_LIST(one_rel); 91*1f5207b7SJohn Levon } else if (cmp_relation(one_rel, two_rel) == 0) { 92*1f5207b7SJohn Levon add_ptr_list(&ret, one_rel); 93*1f5207b7SJohn Levon NEXT_PTR_LIST(one_rel); 94*1f5207b7SJohn Levon NEXT_PTR_LIST(two_rel); 95*1f5207b7SJohn Levon } else { 96*1f5207b7SJohn Levon NEXT_PTR_LIST(two_rel); 97*1f5207b7SJohn Levon } 98*1f5207b7SJohn Levon } 99*1f5207b7SJohn Levon FINISH_PTR_LIST(two_rel); 100*1f5207b7SJohn Levon FINISH_PTR_LIST(one_rel); 101*1f5207b7SJohn Levon 102*1f5207b7SJohn Levon return ret; 103*1f5207b7SJohn Levon } 104*1f5207b7SJohn Levon 105*1f5207b7SJohn Levon static void debug_addition(struct related_list *rlist, const char *name) 106*1f5207b7SJohn Levon { 107*1f5207b7SJohn Levon struct relation *tmp; 108*1f5207b7SJohn Levon 109*1f5207b7SJohn Levon if (!option_debug_related) 110*1f5207b7SJohn Levon return; 111*1f5207b7SJohn Levon 112*1f5207b7SJohn Levon sm_prefix(); 113*1f5207b7SJohn Levon sm_printf("("); 114*1f5207b7SJohn Levon FOR_EACH_PTR(rlist, tmp) { 115*1f5207b7SJohn Levon sm_printf("%s ", tmp->name); 116*1f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 117*1f5207b7SJohn Levon sm_printf(") <-- %s\n", name); 118*1f5207b7SJohn Levon } 119*1f5207b7SJohn Levon 120*1f5207b7SJohn Levon static void add_related(struct related_list **rlist, const char *name, struct symbol *sym) 121*1f5207b7SJohn Levon { 122*1f5207b7SJohn Levon struct relation *rel; 123*1f5207b7SJohn Levon struct relation *new; 124*1f5207b7SJohn Levon struct relation tmp = { 125*1f5207b7SJohn Levon .name = (char *)name, 126*1f5207b7SJohn Levon .sym = sym 127*1f5207b7SJohn Levon }; 128*1f5207b7SJohn Levon 129*1f5207b7SJohn Levon debug_addition(*rlist, name); 130*1f5207b7SJohn Levon 131*1f5207b7SJohn Levon FOR_EACH_PTR(*rlist, rel) { 132*1f5207b7SJohn Levon if (cmp_relation(rel, &tmp) < 0) 133*1f5207b7SJohn Levon continue; 134*1f5207b7SJohn Levon if (cmp_relation(rel, &tmp) == 0) 135*1f5207b7SJohn Levon return; 136*1f5207b7SJohn Levon new = alloc_relation(name, sym); 137*1f5207b7SJohn Levon INSERT_CURRENT(new, rel); 138*1f5207b7SJohn Levon return; 139*1f5207b7SJohn Levon } END_FOR_EACH_PTR(rel); 140*1f5207b7SJohn Levon new = alloc_relation(name, sym); 141*1f5207b7SJohn Levon add_ptr_list(rlist, new); 142*1f5207b7SJohn Levon } 143*1f5207b7SJohn Levon 144*1f5207b7SJohn Levon static struct related_list *del_related(struct smatch_state *state, const char *name, struct symbol *sym) 145*1f5207b7SJohn Levon { 146*1f5207b7SJohn Levon struct relation *tmp; 147*1f5207b7SJohn Levon struct relation remove = { 148*1f5207b7SJohn Levon .name = (char *)name, 149*1f5207b7SJohn Levon .sym = sym, 150*1f5207b7SJohn Levon }; 151*1f5207b7SJohn Levon struct related_list *ret = NULL; 152*1f5207b7SJohn Levon 153*1f5207b7SJohn Levon FOR_EACH_PTR(estate_related(state), tmp) { 154*1f5207b7SJohn Levon if (cmp_relation(tmp, &remove) != 0) 155*1f5207b7SJohn Levon add_ptr_list(&ret, tmp); 156*1f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 157*1f5207b7SJohn Levon 158*1f5207b7SJohn Levon return ret; 159*1f5207b7SJohn Levon } 160*1f5207b7SJohn Levon 161*1f5207b7SJohn Levon void remove_from_equiv(const char *name, struct symbol *sym) 162*1f5207b7SJohn Levon { 163*1f5207b7SJohn Levon struct sm_state *orig_sm; 164*1f5207b7SJohn Levon struct relation *rel; 165*1f5207b7SJohn Levon struct smatch_state *state; 166*1f5207b7SJohn Levon struct related_list *to_update; 167*1f5207b7SJohn Levon 168*1f5207b7SJohn Levon orig_sm = get_sm_state(SMATCH_EXTRA, name, sym); 169*1f5207b7SJohn Levon if (!orig_sm || !get_dinfo(orig_sm->state)->related) 170*1f5207b7SJohn Levon return; 171*1f5207b7SJohn Levon 172*1f5207b7SJohn Levon state = clone_estate(orig_sm->state); 173*1f5207b7SJohn Levon to_update = del_related(state, name, sym); 174*1f5207b7SJohn Levon 175*1f5207b7SJohn Levon FOR_EACH_PTR(to_update, rel) { 176*1f5207b7SJohn Levon struct sm_state *old_sm, *new_sm; 177*1f5207b7SJohn Levon 178*1f5207b7SJohn Levon old_sm = get_sm_state(SMATCH_EXTRA, rel->name, rel->sym); 179*1f5207b7SJohn Levon if (!old_sm) 180*1f5207b7SJohn Levon continue; 181*1f5207b7SJohn Levon 182*1f5207b7SJohn Levon new_sm = clone_sm(old_sm); 183*1f5207b7SJohn Levon get_dinfo(new_sm->state)->related = to_update; 184*1f5207b7SJohn Levon __set_sm(new_sm); 185*1f5207b7SJohn Levon } END_FOR_EACH_PTR(rel); 186*1f5207b7SJohn Levon } 187*1f5207b7SJohn Levon 188*1f5207b7SJohn Levon void remove_from_equiv_expr(struct expression *expr) 189*1f5207b7SJohn Levon { 190*1f5207b7SJohn Levon char *name; 191*1f5207b7SJohn Levon struct symbol *sym; 192*1f5207b7SJohn Levon 193*1f5207b7SJohn Levon name = expr_to_var_sym(expr, &sym); 194*1f5207b7SJohn Levon if (!name || !sym) 195*1f5207b7SJohn Levon goto free; 196*1f5207b7SJohn Levon remove_from_equiv(name, sym); 197*1f5207b7SJohn Levon free: 198*1f5207b7SJohn Levon free_string(name); 199*1f5207b7SJohn Levon } 200*1f5207b7SJohn Levon 201*1f5207b7SJohn Levon void set_related(struct smatch_state *estate, struct related_list *rlist) 202*1f5207b7SJohn Levon { 203*1f5207b7SJohn Levon if (!estate_related(estate) && !rlist) 204*1f5207b7SJohn Levon return; 205*1f5207b7SJohn Levon get_dinfo(estate)->related = rlist; 206*1f5207b7SJohn Levon } 207*1f5207b7SJohn Levon 208*1f5207b7SJohn Levon /* 209*1f5207b7SJohn Levon * set_equiv() is only used for assignments where we set one variable 210*1f5207b7SJohn Levon * equal to the other. a = b;. It's not used for if conditions where 211*1f5207b7SJohn Levon * a == b. 212*1f5207b7SJohn Levon */ 213*1f5207b7SJohn Levon void set_equiv(struct expression *left, struct expression *right) 214*1f5207b7SJohn Levon { 215*1f5207b7SJohn Levon struct sm_state *right_sm, *left_sm; 216*1f5207b7SJohn Levon struct relation *rel; 217*1f5207b7SJohn Levon char *left_name; 218*1f5207b7SJohn Levon struct symbol *left_sym; 219*1f5207b7SJohn Levon struct related_list *rlist; 220*1f5207b7SJohn Levon 221*1f5207b7SJohn Levon left_name = expr_to_var_sym(left, &left_sym); 222*1f5207b7SJohn Levon if (!left_name || !left_sym) 223*1f5207b7SJohn Levon goto free; 224*1f5207b7SJohn Levon 225*1f5207b7SJohn Levon right_sm = get_sm_state_expr(SMATCH_EXTRA, right); 226*1f5207b7SJohn Levon if (!right_sm) 227*1f5207b7SJohn Levon right_sm = set_state_expr(SMATCH_EXTRA, right, alloc_estate_whole(get_type(right))); 228*1f5207b7SJohn Levon if (!right_sm) 229*1f5207b7SJohn Levon goto free; 230*1f5207b7SJohn Levon 231*1f5207b7SJohn Levon /* This block is because we want to preserve the implications. */ 232*1f5207b7SJohn Levon left_sm = clone_sm(right_sm); 233*1f5207b7SJohn Levon left_sm->name = alloc_string(left_name); 234*1f5207b7SJohn Levon left_sm->sym = left_sym; 235*1f5207b7SJohn Levon left_sm->state = clone_estate_cast(get_type(left), right_sm->state); 236*1f5207b7SJohn Levon set_extra_mod_helper(left_name, left_sym, left, left_sm->state); 237*1f5207b7SJohn Levon __set_sm(left_sm); 238*1f5207b7SJohn Levon 239*1f5207b7SJohn Levon rlist = clone_related_list(estate_related(right_sm->state)); 240*1f5207b7SJohn Levon add_related(&rlist, right_sm->name, right_sm->sym); 241*1f5207b7SJohn Levon add_related(&rlist, left_name, left_sym); 242*1f5207b7SJohn Levon 243*1f5207b7SJohn Levon FOR_EACH_PTR(rlist, rel) { 244*1f5207b7SJohn Levon struct sm_state *old_sm, *new_sm; 245*1f5207b7SJohn Levon 246*1f5207b7SJohn Levon old_sm = get_sm_state(SMATCH_EXTRA, rel->name, rel->sym); 247*1f5207b7SJohn Levon if (!old_sm) /* shouldn't happen */ 248*1f5207b7SJohn Levon continue; 249*1f5207b7SJohn Levon new_sm = clone_sm(old_sm); 250*1f5207b7SJohn Levon new_sm->state = clone_estate(old_sm->state); 251*1f5207b7SJohn Levon get_dinfo(new_sm->state)->related = rlist; 252*1f5207b7SJohn Levon __set_sm(new_sm); 253*1f5207b7SJohn Levon } END_FOR_EACH_PTR(rel); 254*1f5207b7SJohn Levon free: 255*1f5207b7SJohn Levon free_string(left_name); 256*1f5207b7SJohn Levon } 257*1f5207b7SJohn Levon 258*1f5207b7SJohn Levon void set_equiv_state_expr(int id, struct expression *expr, struct smatch_state *state) 259*1f5207b7SJohn Levon { 260*1f5207b7SJohn Levon struct relation *rel; 261*1f5207b7SJohn Levon struct smatch_state *estate; 262*1f5207b7SJohn Levon 263*1f5207b7SJohn Levon estate = get_state_expr(SMATCH_EXTRA, expr); 264*1f5207b7SJohn Levon 265*1f5207b7SJohn Levon if (!estate) 266*1f5207b7SJohn Levon return; 267*1f5207b7SJohn Levon 268*1f5207b7SJohn Levon FOR_EACH_PTR(get_dinfo(estate)->related, rel) { 269*1f5207b7SJohn Levon set_state(id, rel->name, rel->sym, state); 270*1f5207b7SJohn Levon } END_FOR_EACH_PTR(rel); 271*1f5207b7SJohn Levon } 272