11506 smatch resync
1 /* 2 * Copyright (C) 2012 Oracle. 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 * This is for functions like: 20 * 21 * void foo(int *x) 22 * { 23 * if (*x == 42) 24 * *x = 0; 25 * } 26 * 27 * The final value of *x depends on the input to the function but with *x == 42 28 * filtered out. 29 * 30 */ 31 32 #include "smatch.h" 33 #include "smatch_extra.h" 34 #include "smatch_slist.h" 35 36 static int my_id; 37 38 static struct stree *start_states; 39 static struct stree_stack *saved_stack; 40 static void save_start_states(struct statement *stmt) 41 { 42 start_states = get_all_states_stree(SMATCH_EXTRA); 43 } 44 45 static void free_start_states(void) 46 { 47 free_stree(&start_states); 48 } 49 50 static void match_save_states(struct expression *expr) 51 { 52 push_stree(&saved_stack, start_states); 53 start_states = NULL; 54 } 55 56 static void match_restore_states(struct expression *expr) 57 { 58 free_stree(&start_states); 59 start_states = pop_stree(&saved_stack); 60 } 61 62 static struct smatch_state *unmatched_state(struct sm_state *sm) 63 { 64 struct smatch_state *state; 65 66 if (parent_is_gone_var_sym(sm->name, sm->sym)) 67 return alloc_estate_empty(); 68 69 state = get_state(SMATCH_EXTRA, sm->name, sm->sym); 70 if (state) 71 return state; 72 return alloc_estate_whole(estate_type(sm->state)); 73 } 74 75 static void pre_merge_hook(struct sm_state *sm) 76 { 77 struct smatch_state *extra, *mine; 78 struct range_list *rl; 79 80 if (estate_rl(sm->state)) 81 return; 82 83 extra = get_state(SMATCH_EXTRA, sm->name, sm->sym); 84 if (!extra) 85 return; 86 mine = get_state(my_id, sm->name, sm->sym); 87 88 rl = rl_intersection(estate_rl(extra), estate_rl(mine)); 89 if (rl_equiv(rl, estate_rl(mine))) 90 return; 91 set_state(my_id, sm->name, sm->sym, alloc_estate_rl(clone_rl(rl))); 92 } 93 94 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state) 95 { 96 int param; 97 98 if (__in_fake_assign) 99 return; 100 101 param = get_param_num_from_sym(sym); 102 if (param < 0) 103 return; 104 105 /* on stack parameters are handled in smatch_param_limit.c */ 106 if (sym->ident && strcmp(sym->ident->name, name) == 0) 107 return; 108 109 set_state(my_id, name, sym, alloc_estate_empty()); 110 } 111 112 /* 113 * This relies on the fact that these states are stored so that 114 * foo->bar is before foo->bar->baz. 115 */ 116 static int parent_set(struct string_list *list, const char *name) 117 { 118 char *tmp; 119 int len; 120 int ret; 121 122 FOR_EACH_PTR(list, tmp) { 123 len = strlen(tmp); 124 ret = strncmp(tmp, name, len); 125 if (ret < 0) 126 continue; 127 if (ret > 0) 128 return 0; 129 if (name[len] == '-') 130 return 1; 131 } END_FOR_EACH_PTR(tmp); 132 133 return 0; 134 } 135 136 static void print_one_mod_param(int return_id, char *return_ranges, 137 int param, struct sm_state *sm, struct string_list **totally_filtered) 138 { 139 const char *param_name; 140 141 param_name = get_param_name(sm); 142 if (!param_name) 143 return; 144 if (is_whole_rl(estate_rl(sm->state))) 145 return; 146 if (!estate_rl(sm->state)) { 147 insert_string(totally_filtered, (char *)sm->name); 148 return; 149 } 150 151 sql_insert_return_states(return_id, return_ranges, PARAM_FILTER, param, 152 param_name, show_rl(estate_rl(sm->state))); 153 } 154 155 static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr) 156 { 157 struct sm_state *tmp; 158 struct sm_state *sm; 159 struct string_list *totally_filtered = NULL; 160 int param; 161 162 FOR_EACH_MY_SM(SMATCH_EXTRA, __get_cur_stree(), tmp) { 163 param = get_param_num_from_sym(tmp->sym); 164 if (param < 0) 165 continue; 166 167 /* on stack parameters are handled in smatch_param_limit.c */ 168 if (tmp->sym->ident && strcmp(tmp->sym->ident->name, tmp->name) == 0) 169 continue; 170 171 if (parent_set(totally_filtered, tmp->name)) 172 continue; 173 174 sm = get_sm_state(my_id, tmp->name, tmp->sym); 175 if (sm) 176 print_one_mod_param(return_id, return_ranges, param, sm, &totally_filtered); 177 } END_FOR_EACH_SM(tmp); 178 179 free_ptr_list((struct ptr_list **)&totally_filtered); 180 } 181 182 int param_has_filter_data(struct sm_state *sm) 183 { 184 struct smatch_state *state; 185 186 state = get_state(my_id, sm->name, sm->sym); 187 if (!state) { 188 if (get_assigned_expr_name_sym(sm->name, sm->sym)) 189 return 0; 190 return 1; 191 } 192 if (estate_rl(state)) 193 return 1; 194 return 0; 195 } 196 197 void register_param_filter(int id) 198 { 199 my_id = id; 200 201 add_hook(&save_start_states, AFTER_DEF_HOOK); 202 add_hook(&free_start_states, AFTER_FUNC_HOOK); 203 204 add_extra_mod_hook(&extra_mod_hook); 205 add_unmatched_state_hook(my_id, &unmatched_state); 206 add_pre_merge_hook(my_id, &pre_merge_hook); 207 add_merge_hook(my_id, &merge_estates); 208 209 add_hook(&match_save_states, INLINE_FN_START); 210 add_hook(&match_restore_states, INLINE_FN_END); 211 212 add_split_return_callback(&print_return_value_param); 213 } 214 --- EOF ---