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 if (is_ignored_kernel_data(param_name)) { 152 insert_string(totally_filtered, (char *)sm->name); 153 return; 154 } 155 156 sql_insert_return_states(return_id, return_ranges, PARAM_FILTER, param, 157 param_name, show_rl(estate_rl(sm->state))); 158 } 159 160 static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr) 161 { 162 struct sm_state *tmp; 163 struct sm_state *sm; 164 struct string_list *totally_filtered = NULL; 165 int param; 166 167 FOR_EACH_MY_SM(SMATCH_EXTRA, __get_cur_stree(), tmp) { 168 param = get_param_num_from_sym(tmp->sym); 169 if (param < 0) 170 continue; 171 172 /* on stack parameters are handled in smatch_param_limit.c */ 173 if (tmp->sym->ident && strcmp(tmp->sym->ident->name, tmp->name) == 0) 174 continue; 175 176 if (parent_set(totally_filtered, tmp->name)) 177 continue; 178 179 sm = get_sm_state(my_id, tmp->name, tmp->sym); 180 if (sm) 181 print_one_mod_param(return_id, return_ranges, param, sm, &totally_filtered); 182 } END_FOR_EACH_SM(tmp); 183 184 free_ptr_list((struct ptr_list **)&totally_filtered); 185 } 186 187 int param_has_filter_data(struct sm_state *sm) 188 { 189 struct smatch_state *state; 190 191 state = get_state(my_id, sm->name, sm->sym); 192 if (!state) { 193 if (get_assigned_expr_name_sym(sm->name, sm->sym)) 194 return 0; 195 return 1; 196 } 197 if (estate_rl(state)) 198 return 1; 199 return 0; 200 } 201 202 void register_param_filter(int id) 203 { 204 my_id = id; 205 206 set_dynamic_states(my_id); 207 add_hook(&save_start_states, AFTER_DEF_HOOK); 208 add_hook(&free_start_states, AFTER_FUNC_HOOK); 209 210 add_extra_mod_hook(&extra_mod_hook); 211 add_unmatched_state_hook(my_id, &unmatched_state); 212 add_pre_merge_hook(my_id, &pre_merge_hook); 213 add_merge_hook(my_id, &merge_estates); 214 215 add_hook(&match_save_states, INLINE_FN_START); 216 add_hook(&match_restore_states, INLINE_FN_END); 217 218 add_split_return_callback(&print_return_value_param); 219 } 220 --- EOF ---