1*1f5207b7SJohn Levon /* 2*1f5207b7SJohn Levon * Copyright (C) 2012 Oracle. 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 almost the same as smatch_param_filter.c. The difference is that 20*1f5207b7SJohn Levon * this only deals with values passed on the stack and param filter only deals 21*1f5207b7SJohn Levon * with values changed so that the caller sees the new value. It other words 22*1f5207b7SJohn Levon * the key for these should always be "$" and the key for param_filter should 23*1f5207b7SJohn Levon * never be "$". Also smatch_param_set() should never use "$" as the key. 24*1f5207b7SJohn Levon * Param set should work together with param_filter to determine the value that 25*1f5207b7SJohn Levon * the caller sees at the end. 26*1f5207b7SJohn Levon * 27*1f5207b7SJohn Levon * This is for functions like this: 28*1f5207b7SJohn Levon * 29*1f5207b7SJohn Levon * int foo(int a) 30*1f5207b7SJohn Levon * { 31*1f5207b7SJohn Levon * if (a >= 0 && a < 10) { 32*1f5207b7SJohn Levon * a = 42; 33*1f5207b7SJohn Levon * return 1; 34*1f5207b7SJohn Levon * } 35*1f5207b7SJohn Levon * return 0; 36*1f5207b7SJohn Levon * } 37*1f5207b7SJohn Levon * 38*1f5207b7SJohn Levon * If we pass in 5, it returns 1. 39*1f5207b7SJohn Levon * 40*1f5207b7SJohn Levon * It's a bit complicated because we can't just consider the final value, we 41*1f5207b7SJohn Levon * have to always consider the passed in value. 42*1f5207b7SJohn Levon * 43*1f5207b7SJohn Levon */ 44*1f5207b7SJohn Levon 45*1f5207b7SJohn Levon #include "scope.h" 46*1f5207b7SJohn Levon #include "smatch.h" 47*1f5207b7SJohn Levon #include "smatch_extra.h" 48*1f5207b7SJohn Levon #include "smatch_slist.h" 49*1f5207b7SJohn Levon 50*1f5207b7SJohn Levon static int my_id; 51*1f5207b7SJohn Levon 52*1f5207b7SJohn Levon static struct stree *start_states; 53*1f5207b7SJohn Levon static struct stree_stack *saved_stack; 54*1f5207b7SJohn Levon 55*1f5207b7SJohn Levon static void save_start_states(struct statement *stmt) 56*1f5207b7SJohn Levon { 57*1f5207b7SJohn Levon start_states = get_all_states_stree(SMATCH_EXTRA); 58*1f5207b7SJohn Levon } 59*1f5207b7SJohn Levon 60*1f5207b7SJohn Levon static void free_start_states(void) 61*1f5207b7SJohn Levon { 62*1f5207b7SJohn Levon free_stree(&start_states); 63*1f5207b7SJohn Levon } 64*1f5207b7SJohn Levon 65*1f5207b7SJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm) 66*1f5207b7SJohn Levon { 67*1f5207b7SJohn Levon struct smatch_state *state; 68*1f5207b7SJohn Levon 69*1f5207b7SJohn Levon state = get_state(SMATCH_EXTRA, sm->name, sm->sym); 70*1f5207b7SJohn Levon if (state) 71*1f5207b7SJohn Levon return state; 72*1f5207b7SJohn Levon return alloc_estate_whole(estate_type(sm->state)); 73*1f5207b7SJohn Levon } 74*1f5207b7SJohn Levon 75*1f5207b7SJohn Levon struct smatch_state *get_orig_estate(const char *name, struct symbol *sym) 76*1f5207b7SJohn Levon { 77*1f5207b7SJohn Levon struct smatch_state *state; 78*1f5207b7SJohn Levon 79*1f5207b7SJohn Levon state = get_state(my_id, name, sym); 80*1f5207b7SJohn Levon if (state) 81*1f5207b7SJohn Levon return state; 82*1f5207b7SJohn Levon 83*1f5207b7SJohn Levon state = get_state(SMATCH_EXTRA, name, sym); 84*1f5207b7SJohn Levon if (state) 85*1f5207b7SJohn Levon return state; 86*1f5207b7SJohn Levon return alloc_estate_rl(alloc_whole_rl(get_real_base_type(sym))); 87*1f5207b7SJohn Levon } 88*1f5207b7SJohn Levon 89*1f5207b7SJohn Levon struct smatch_state *get_orig_estate_type(const char *name, struct symbol *sym, struct symbol *type) 90*1f5207b7SJohn Levon { 91*1f5207b7SJohn Levon struct smatch_state *state; 92*1f5207b7SJohn Levon 93*1f5207b7SJohn Levon state = get_state(my_id, name, sym); 94*1f5207b7SJohn Levon if (state) 95*1f5207b7SJohn Levon return state; 96*1f5207b7SJohn Levon 97*1f5207b7SJohn Levon state = get_state(SMATCH_EXTRA, name, sym); 98*1f5207b7SJohn Levon if (state) 99*1f5207b7SJohn Levon return state; 100*1f5207b7SJohn Levon return alloc_estate_rl(alloc_whole_rl(type)); 101*1f5207b7SJohn Levon } 102*1f5207b7SJohn Levon 103*1f5207b7SJohn Levon static struct range_list *generify_mtag_range(struct smatch_state *state) 104*1f5207b7SJohn Levon { 105*1f5207b7SJohn Levon struct range_list *rl; 106*1f5207b7SJohn Levon struct data_range *drange; 107*1f5207b7SJohn Levon 108*1f5207b7SJohn Levon if (!estate_type(state) || estate_type(state)->type != SYM_PTR) 109*1f5207b7SJohn Levon return estate_rl(state); 110*1f5207b7SJohn Levon 111*1f5207b7SJohn Levon /* 112*1f5207b7SJohn Levon * The problem is that we get too specific on our param limits when we 113*1f5207b7SJohn Levon * know exactly what pointers are passed to a function. It gets to the 114*1f5207b7SJohn Levon * point where we say "pointer x will succeed, but everything else will 115*1f5207b7SJohn Levon * fail." And then we introduce a new caller which passes a different 116*1f5207b7SJohn Levon * pointer and it's like, "Sorry bro, that's not possible." 117*1f5207b7SJohn Levon * 118*1f5207b7SJohn Levon */ 119*1f5207b7SJohn Levon rl = rl_intersection(estate_rl(state), valid_ptr_rl); 120*1f5207b7SJohn Levon if (!rl) 121*1f5207b7SJohn Levon return estate_rl(state); 122*1f5207b7SJohn Levon 123*1f5207b7SJohn Levon FOR_EACH_PTR(rl, drange) { 124*1f5207b7SJohn Levon if (drange->min.value != drange->max.value) 125*1f5207b7SJohn Levon continue; 126*1f5207b7SJohn Levon if (drange->min.value > -4096 && drange->min.value <= 0) 127*1f5207b7SJohn Levon continue; 128*1f5207b7SJohn Levon return rl_union(valid_ptr_rl, rl); 129*1f5207b7SJohn Levon } END_FOR_EACH_PTR(drange); 130*1f5207b7SJohn Levon 131*1f5207b7SJohn Levon return estate_rl(state); 132*1f5207b7SJohn Levon } 133*1f5207b7SJohn Levon 134*1f5207b7SJohn Levon static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr) 135*1f5207b7SJohn Levon { 136*1f5207b7SJohn Levon struct smatch_state *state, *old; 137*1f5207b7SJohn Levon struct sm_state *tmp; 138*1f5207b7SJohn Levon struct range_list *rl; 139*1f5207b7SJohn Levon const char *param_name; 140*1f5207b7SJohn Levon int param; 141*1f5207b7SJohn Levon 142*1f5207b7SJohn Levon FOR_EACH_MY_SM(SMATCH_EXTRA, __get_cur_stree(), tmp) { 143*1f5207b7SJohn Levon param = get_param_num_from_sym(tmp->sym); 144*1f5207b7SJohn Levon if (param < 0) 145*1f5207b7SJohn Levon continue; 146*1f5207b7SJohn Levon 147*1f5207b7SJohn Levon param_name = get_param_name(tmp); 148*1f5207b7SJohn Levon if (!param_name) 149*1f5207b7SJohn Levon continue; 150*1f5207b7SJohn Levon 151*1f5207b7SJohn Levon state = __get_state(my_id, tmp->name, tmp->sym); 152*1f5207b7SJohn Levon if (!state) 153*1f5207b7SJohn Levon state = tmp->state; 154*1f5207b7SJohn Levon 155*1f5207b7SJohn Levon if (estate_is_whole(state) || estate_is_empty(state)) 156*1f5207b7SJohn Levon continue; 157*1f5207b7SJohn Levon old = get_state_stree(start_states, SMATCH_EXTRA, tmp->name, tmp->sym); 158*1f5207b7SJohn Levon if (old && rl_equiv(estate_rl(old), estate_rl(state))) 159*1f5207b7SJohn Levon continue; 160*1f5207b7SJohn Levon 161*1f5207b7SJohn Levon rl = generify_mtag_range(state); 162*1f5207b7SJohn Levon sql_insert_return_states(return_id, return_ranges, PARAM_LIMIT, 163*1f5207b7SJohn Levon param, param_name, show_rl(rl)); 164*1f5207b7SJohn Levon } END_FOR_EACH_SM(tmp); 165*1f5207b7SJohn Levon } 166*1f5207b7SJohn Levon 167*1f5207b7SJohn Levon static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state) 168*1f5207b7SJohn Levon { 169*1f5207b7SJohn Levon struct smatch_state *orig_vals; 170*1f5207b7SJohn Levon int param; 171*1f5207b7SJohn Levon 172*1f5207b7SJohn Levon param = get_param_num_from_sym(sym); 173*1f5207b7SJohn Levon if (param < 0) 174*1f5207b7SJohn Levon return; 175*1f5207b7SJohn Levon 176*1f5207b7SJohn Levon orig_vals = get_orig_estate_type(name, sym, estate_type(state)); 177*1f5207b7SJohn Levon set_state(my_id, name, sym, orig_vals); 178*1f5207b7SJohn Levon } 179*1f5207b7SJohn Levon 180*1f5207b7SJohn Levon static void match_save_states(struct expression *expr) 181*1f5207b7SJohn Levon { 182*1f5207b7SJohn Levon push_stree(&saved_stack, start_states); 183*1f5207b7SJohn Levon start_states = NULL; 184*1f5207b7SJohn Levon } 185*1f5207b7SJohn Levon 186*1f5207b7SJohn Levon static void match_restore_states(struct expression *expr) 187*1f5207b7SJohn Levon { 188*1f5207b7SJohn Levon free_stree(&start_states); 189*1f5207b7SJohn Levon start_states = pop_stree(&saved_stack); 190*1f5207b7SJohn Levon } 191*1f5207b7SJohn Levon 192*1f5207b7SJohn Levon void register_param_limit(int id) 193*1f5207b7SJohn Levon { 194*1f5207b7SJohn Levon my_id = id; 195*1f5207b7SJohn Levon 196*1f5207b7SJohn Levon add_hook(&save_start_states, AFTER_DEF_HOOK); 197*1f5207b7SJohn Levon add_hook(&free_start_states, AFTER_FUNC_HOOK); 198*1f5207b7SJohn Levon 199*1f5207b7SJohn Levon add_extra_mod_hook(&extra_mod_hook); 200*1f5207b7SJohn Levon add_unmatched_state_hook(my_id, &unmatched_state); 201*1f5207b7SJohn Levon add_merge_hook(my_id, &merge_estates); 202*1f5207b7SJohn Levon 203*1f5207b7SJohn Levon add_hook(&match_save_states, INLINE_FN_START); 204*1f5207b7SJohn Levon add_hook(&match_restore_states, INLINE_FN_END); 205*1f5207b7SJohn Levon 206*1f5207b7SJohn Levon add_split_return_callback(&print_return_value_param); 207*1f5207b7SJohn Levon } 208*1f5207b7SJohn Levon 209