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 for functions like: 20*1f5207b7SJohn Levon * 21*1f5207b7SJohn Levon * int foo(int *x) 22*1f5207b7SJohn Levon * { 23*1f5207b7SJohn Levon * if (*x == 42) { 24*1f5207b7SJohn Levon * *x = 0; 25*1f5207b7SJohn Levon * return 1; 26*1f5207b7SJohn Levon * } 27*1f5207b7SJohn Levon * return 0; 28*1f5207b7SJohn Levon * } 29*1f5207b7SJohn Levon * 30*1f5207b7SJohn Levon * If we return 1 that means the value of *x has been set to 0. If we return 31*1f5207b7SJohn Levon * 0 then we have left *x alone. 32*1f5207b7SJohn Levon * 33*1f5207b7SJohn Levon */ 34*1f5207b7SJohn Levon 35*1f5207b7SJohn Levon #include "scope.h" 36*1f5207b7SJohn Levon #include "smatch.h" 37*1f5207b7SJohn Levon #include "smatch_slist.h" 38*1f5207b7SJohn Levon #include "smatch_extra.h" 39*1f5207b7SJohn Levon 40*1f5207b7SJohn Levon static int my_id; 41*1f5207b7SJohn Levon 42*1f5207b7SJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm) 43*1f5207b7SJohn Levon { 44*1f5207b7SJohn Levon return alloc_estate_empty(); 45*1f5207b7SJohn Levon } 46*1f5207b7SJohn Levon 47*1f5207b7SJohn Levon static int parent_is_set(const char *name, struct symbol *sym, struct smatch_state *state) 48*1f5207b7SJohn Levon { 49*1f5207b7SJohn Levon struct expression *faked; 50*1f5207b7SJohn Levon char *left_name; 51*1f5207b7SJohn Levon int ret = 0; 52*1f5207b7SJohn Levon int len; 53*1f5207b7SJohn Levon 54*1f5207b7SJohn Levon if (!__in_fake_assign) 55*1f5207b7SJohn Levon return 0; 56*1f5207b7SJohn Levon if (!is_whole_rl(estate_rl(state))) 57*1f5207b7SJohn Levon return 0; 58*1f5207b7SJohn Levon if (get_state(my_id, name, sym)) 59*1f5207b7SJohn Levon return 0; 60*1f5207b7SJohn Levon 61*1f5207b7SJohn Levon faked = get_faked_expression(); 62*1f5207b7SJohn Levon if (!faked) 63*1f5207b7SJohn Levon return 0; 64*1f5207b7SJohn Levon if ((faked->type == EXPR_PREOP || faked->type == EXPR_POSTOP) && 65*1f5207b7SJohn Levon (faked->op == SPECIAL_INCREMENT || faked->op == SPECIAL_DECREMENT)) { 66*1f5207b7SJohn Levon faked = strip_expr(faked->unop); 67*1f5207b7SJohn Levon if (faked->type == EXPR_SYMBOL) 68*1f5207b7SJohn Levon return 1; 69*1f5207b7SJohn Levon return 0; 70*1f5207b7SJohn Levon } 71*1f5207b7SJohn Levon if (faked->type != EXPR_ASSIGNMENT) 72*1f5207b7SJohn Levon return 0; 73*1f5207b7SJohn Levon 74*1f5207b7SJohn Levon left_name = expr_to_var(faked->left); 75*1f5207b7SJohn Levon if (!left_name) 76*1f5207b7SJohn Levon return 0; 77*1f5207b7SJohn Levon 78*1f5207b7SJohn Levon len = strlen(left_name); 79*1f5207b7SJohn Levon if (strncmp(name, left_name, len) == 0 && name[len] == '-') 80*1f5207b7SJohn Levon ret = 1; 81*1f5207b7SJohn Levon free_string(left_name); 82*1f5207b7SJohn Levon 83*1f5207b7SJohn Levon return ret; 84*1f5207b7SJohn Levon } 85*1f5207b7SJohn Levon 86*1f5207b7SJohn Levon static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state) 87*1f5207b7SJohn Levon { 88*1f5207b7SJohn Levon if (parent_is_set(name, sym, state)) 89*1f5207b7SJohn Levon return; 90*1f5207b7SJohn Levon if (get_param_num_from_sym(sym) < 0) 91*1f5207b7SJohn Levon return; 92*1f5207b7SJohn Levon set_state(my_id, name, sym, state); 93*1f5207b7SJohn Levon } 94*1f5207b7SJohn Levon 95*1f5207b7SJohn Levon /* 96*1f5207b7SJohn Levon * This function is is a dirty hack because extra_mod_hook is giving us a NULL 97*1f5207b7SJohn Levon * sym instead of a vsl. 98*1f5207b7SJohn Levon */ 99*1f5207b7SJohn Levon static void match_array_assignment(struct expression *expr) 100*1f5207b7SJohn Levon { 101*1f5207b7SJohn Levon struct expression *array, *offset; 102*1f5207b7SJohn Levon char *name; 103*1f5207b7SJohn Levon struct symbol *sym; 104*1f5207b7SJohn Levon struct range_list *rl; 105*1f5207b7SJohn Levon sval_t sval; 106*1f5207b7SJohn Levon char buf[256]; 107*1f5207b7SJohn Levon 108*1f5207b7SJohn Levon if (__in_fake_assign) 109*1f5207b7SJohn Levon return; 110*1f5207b7SJohn Levon 111*1f5207b7SJohn Levon if (!is_array(expr->left)) 112*1f5207b7SJohn Levon return; 113*1f5207b7SJohn Levon array = get_array_base(expr->left); 114*1f5207b7SJohn Levon offset = get_array_offset(expr->left); 115*1f5207b7SJohn Levon 116*1f5207b7SJohn Levon /* These are handled by extra_mod_hook() */ 117*1f5207b7SJohn Levon if (get_value(offset, &sval)) 118*1f5207b7SJohn Levon return; 119*1f5207b7SJohn Levon name = expr_to_var_sym(array, &sym); 120*1f5207b7SJohn Levon if (!name || !sym) 121*1f5207b7SJohn Levon goto free; 122*1f5207b7SJohn Levon if (get_param_num_from_sym(sym) < 0) 123*1f5207b7SJohn Levon goto free; 124*1f5207b7SJohn Levon get_absolute_rl(expr->right, &rl); 125*1f5207b7SJohn Levon rl = cast_rl(get_type(expr->left), rl); 126*1f5207b7SJohn Levon 127*1f5207b7SJohn Levon snprintf(buf, sizeof(buf), "*%s", name); 128*1f5207b7SJohn Levon set_state(my_id, buf, sym, alloc_estate_rl(rl)); 129*1f5207b7SJohn Levon free: 130*1f5207b7SJohn Levon free_string(name); 131*1f5207b7SJohn Levon } 132*1f5207b7SJohn Levon 133*1f5207b7SJohn Levon /* 134*1f5207b7SJohn Levon * This relies on the fact that these states are stored so that 135*1f5207b7SJohn Levon * foo->bar is before foo->bar->baz. 136*1f5207b7SJohn Levon */ 137*1f5207b7SJohn Levon static int parent_set(struct string_list *list, const char *name) 138*1f5207b7SJohn Levon { 139*1f5207b7SJohn Levon char *tmp; 140*1f5207b7SJohn Levon int len; 141*1f5207b7SJohn Levon int ret; 142*1f5207b7SJohn Levon 143*1f5207b7SJohn Levon FOR_EACH_PTR(list, tmp) { 144*1f5207b7SJohn Levon len = strlen(tmp); 145*1f5207b7SJohn Levon ret = strncmp(tmp, name, len); 146*1f5207b7SJohn Levon if (ret < 0) 147*1f5207b7SJohn Levon continue; 148*1f5207b7SJohn Levon if (ret > 0) 149*1f5207b7SJohn Levon return 0; 150*1f5207b7SJohn Levon if (name[len] == '-') 151*1f5207b7SJohn Levon return 1; 152*1f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 153*1f5207b7SJohn Levon 154*1f5207b7SJohn Levon return 0; 155*1f5207b7SJohn Levon } 156*1f5207b7SJohn Levon 157*1f5207b7SJohn Levon static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr) 158*1f5207b7SJohn Levon { 159*1f5207b7SJohn Levon struct sm_state *sm; 160*1f5207b7SJohn Levon struct smatch_state *extra; 161*1f5207b7SJohn Levon int param; 162*1f5207b7SJohn Levon struct range_list *rl; 163*1f5207b7SJohn Levon const char *param_name; 164*1f5207b7SJohn Levon struct string_list *set_list = NULL; 165*1f5207b7SJohn Levon char *math_str; 166*1f5207b7SJohn Levon char buf[256]; 167*1f5207b7SJohn Levon sval_t sval; 168*1f5207b7SJohn Levon 169*1f5207b7SJohn Levon FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) { 170*1f5207b7SJohn Levon if (!estate_rl(sm->state)) 171*1f5207b7SJohn Levon continue; 172*1f5207b7SJohn Levon extra = get_state(SMATCH_EXTRA, sm->name, sm->sym); 173*1f5207b7SJohn Levon if (extra) { 174*1f5207b7SJohn Levon rl = rl_intersection(estate_rl(sm->state), estate_rl(extra)); 175*1f5207b7SJohn Levon if (!rl) 176*1f5207b7SJohn Levon continue; 177*1f5207b7SJohn Levon } else { 178*1f5207b7SJohn Levon rl = estate_rl(sm->state); 179*1f5207b7SJohn Levon } 180*1f5207b7SJohn Levon 181*1f5207b7SJohn Levon param = get_param_num_from_sym(sm->sym); 182*1f5207b7SJohn Levon if (param < 0) 183*1f5207b7SJohn Levon continue; 184*1f5207b7SJohn Levon param_name = get_param_name(sm); 185*1f5207b7SJohn Levon if (!param_name) 186*1f5207b7SJohn Levon continue; 187*1f5207b7SJohn Levon if (strcmp(param_name, "$") == 0) { 188*1f5207b7SJohn Levon insert_string(&set_list, (char *)sm->name); 189*1f5207b7SJohn Levon continue; 190*1f5207b7SJohn Levon } 191*1f5207b7SJohn Levon 192*1f5207b7SJohn Levon if (rl_to_sval(rl, &sval)) { 193*1f5207b7SJohn Levon insert_string(&set_list, (char *)sm->name); 194*1f5207b7SJohn Levon sql_insert_return_states(return_id, return_ranges, 195*1f5207b7SJohn Levon param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET, 196*1f5207b7SJohn Levon param, param_name, show_rl(rl)); 197*1f5207b7SJohn Levon continue; 198*1f5207b7SJohn Levon } 199*1f5207b7SJohn Levon 200*1f5207b7SJohn Levon math_str = get_value_in_terms_of_parameter_math_var_sym(sm->name, sm->sym); 201*1f5207b7SJohn Levon if (math_str) { 202*1f5207b7SJohn Levon snprintf(buf, sizeof(buf), "%s[%s]", show_rl(rl), math_str); 203*1f5207b7SJohn Levon insert_string(&set_list, (char *)sm->name); 204*1f5207b7SJohn Levon sql_insert_return_states(return_id, return_ranges, 205*1f5207b7SJohn Levon param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET, 206*1f5207b7SJohn Levon param, param_name, buf); 207*1f5207b7SJohn Levon continue; 208*1f5207b7SJohn Levon } 209*1f5207b7SJohn Levon 210*1f5207b7SJohn Levon /* no useful information here. */ 211*1f5207b7SJohn Levon if (is_whole_rl(rl) && parent_set(set_list, sm->name)) 212*1f5207b7SJohn Levon continue; 213*1f5207b7SJohn Levon insert_string(&set_list, (char *)sm->name); 214*1f5207b7SJohn Levon 215*1f5207b7SJohn Levon sql_insert_return_states(return_id, return_ranges, 216*1f5207b7SJohn Levon param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET, 217*1f5207b7SJohn Levon param, param_name, show_rl(rl)); 218*1f5207b7SJohn Levon 219*1f5207b7SJohn Levon } END_FOR_EACH_SM(sm); 220*1f5207b7SJohn Levon 221*1f5207b7SJohn Levon free_ptr_list((struct ptr_list **)&set_list); 222*1f5207b7SJohn Levon } 223*1f5207b7SJohn Levon 224*1f5207b7SJohn Levon int param_was_set_var_sym(const char *name, struct symbol *sym) 225*1f5207b7SJohn Levon { 226*1f5207b7SJohn Levon struct sm_state *sm; 227*1f5207b7SJohn Levon int len; 228*1f5207b7SJohn Levon 229*1f5207b7SJohn Levon FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) { 230*1f5207b7SJohn Levon if (sm->sym != sym) 231*1f5207b7SJohn Levon continue; 232*1f5207b7SJohn Levon len = strlen(sm->name); 233*1f5207b7SJohn Levon if (strncmp(sm->name, name, len) != 0) 234*1f5207b7SJohn Levon continue; 235*1f5207b7SJohn Levon if (name[len] == '\0' || 236*1f5207b7SJohn Levon name[len] == '-') 237*1f5207b7SJohn Levon return 1; 238*1f5207b7SJohn Levon } END_FOR_EACH_SM(sm); 239*1f5207b7SJohn Levon 240*1f5207b7SJohn Levon return 0; 241*1f5207b7SJohn Levon } 242*1f5207b7SJohn Levon 243*1f5207b7SJohn Levon int param_was_set(struct expression *expr) 244*1f5207b7SJohn Levon { 245*1f5207b7SJohn Levon char *name; 246*1f5207b7SJohn Levon struct symbol *sym; 247*1f5207b7SJohn Levon int ret = 0; 248*1f5207b7SJohn Levon 249*1f5207b7SJohn Levon name = expr_to_var_sym(expr, &sym); 250*1f5207b7SJohn Levon if (!name || !sym) 251*1f5207b7SJohn Levon goto free; 252*1f5207b7SJohn Levon 253*1f5207b7SJohn Levon ret = param_was_set_var_sym(name, sym); 254*1f5207b7SJohn Levon free: 255*1f5207b7SJohn Levon free_string(name); 256*1f5207b7SJohn Levon return ret; 257*1f5207b7SJohn Levon } 258*1f5207b7SJohn Levon 259*1f5207b7SJohn Levon void register_param_set(int id) 260*1f5207b7SJohn Levon { 261*1f5207b7SJohn Levon my_id = id; 262*1f5207b7SJohn Levon 263*1f5207b7SJohn Levon add_extra_mod_hook(&extra_mod_hook); 264*1f5207b7SJohn Levon add_hook(match_array_assignment, ASSIGNMENT_HOOK); 265*1f5207b7SJohn Levon add_unmatched_state_hook(my_id, &unmatched_state); 266*1f5207b7SJohn Levon add_merge_hook(my_id, &merge_estates); 267*1f5207b7SJohn Levon add_split_return_callback(&print_return_value_param); 268*1f5207b7SJohn Levon } 269*1f5207b7SJohn Levon 270