11f5207b7SJohn Levon /* 21f5207b7SJohn Levon * Copyright (C) 2012 Oracle. 31f5207b7SJohn Levon * 41f5207b7SJohn Levon * This program is free software; you can redistribute it and/or 51f5207b7SJohn Levon * modify it under the terms of the GNU General Public License 61f5207b7SJohn Levon * as published by the Free Software Foundation; either version 2 71f5207b7SJohn Levon * of the License, or (at your option) any later version. 81f5207b7SJohn Levon * 91f5207b7SJohn Levon * This program is distributed in the hope that it will be useful, 101f5207b7SJohn Levon * but WITHOUT ANY WARRANTY; without even the implied warranty of 111f5207b7SJohn Levon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 121f5207b7SJohn Levon * GNU General Public License for more details. 131f5207b7SJohn Levon * 141f5207b7SJohn Levon * You should have received a copy of the GNU General Public License 151f5207b7SJohn Levon * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt 161f5207b7SJohn Levon */ 171f5207b7SJohn Levon 181f5207b7SJohn Levon /* 191f5207b7SJohn Levon * This is almost the same as smatch_param_filter.c. The difference is that 201f5207b7SJohn Levon * this only deals with values passed on the stack and param filter only deals 211f5207b7SJohn Levon * with values changed so that the caller sees the new value. It other words 221f5207b7SJohn Levon * the key for these should always be "$" and the key for param_filter should 231f5207b7SJohn Levon * never be "$". Also smatch_param_set() should never use "$" as the key. 241f5207b7SJohn Levon * Param set should work together with param_filter to determine the value that 251f5207b7SJohn Levon * the caller sees at the end. 261f5207b7SJohn Levon * 271f5207b7SJohn Levon * This is for functions like this: 281f5207b7SJohn Levon * 291f5207b7SJohn Levon * int foo(int a) 301f5207b7SJohn Levon * { 311f5207b7SJohn Levon * if (a >= 0 && a < 10) { 321f5207b7SJohn Levon * a = 42; 331f5207b7SJohn Levon * return 1; 341f5207b7SJohn Levon * } 351f5207b7SJohn Levon * return 0; 361f5207b7SJohn Levon * } 371f5207b7SJohn Levon * 381f5207b7SJohn Levon * If we pass in 5, it returns 1. 391f5207b7SJohn Levon * 401f5207b7SJohn Levon * It's a bit complicated because we can't just consider the final value, we 411f5207b7SJohn Levon * have to always consider the passed in value. 421f5207b7SJohn Levon * 431f5207b7SJohn Levon */ 441f5207b7SJohn Levon 451f5207b7SJohn Levon #include "scope.h" 461f5207b7SJohn Levon #include "smatch.h" 471f5207b7SJohn Levon #include "smatch_extra.h" 481f5207b7SJohn Levon #include "smatch_slist.h" 491f5207b7SJohn Levon 501f5207b7SJohn Levon static int my_id; 511f5207b7SJohn Levon 521f5207b7SJohn Levon static struct stree *start_states; 531f5207b7SJohn Levon static struct stree_stack *saved_stack; 541f5207b7SJohn Levon 551f5207b7SJohn Levon static void save_start_states(struct statement *stmt) 561f5207b7SJohn Levon { 571f5207b7SJohn Levon start_states = get_all_states_stree(SMATCH_EXTRA); 581f5207b7SJohn Levon } 591f5207b7SJohn Levon 601f5207b7SJohn Levon static void free_start_states(void) 611f5207b7SJohn Levon { 621f5207b7SJohn Levon free_stree(&start_states); 631f5207b7SJohn Levon } 641f5207b7SJohn Levon 651f5207b7SJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm) 661f5207b7SJohn Levon { 671f5207b7SJohn Levon struct smatch_state *state; 681f5207b7SJohn Levon 69*c85f09ccSJohn Levon state = __get_state(SMATCH_EXTRA, sm->name, sm->sym); 701f5207b7SJohn Levon if (state) 711f5207b7SJohn Levon return state; 721f5207b7SJohn Levon return alloc_estate_whole(estate_type(sm->state)); 731f5207b7SJohn Levon } 741f5207b7SJohn Levon 751f5207b7SJohn Levon struct smatch_state *get_orig_estate(const char *name, struct symbol *sym) 761f5207b7SJohn Levon { 771f5207b7SJohn Levon struct smatch_state *state; 781f5207b7SJohn Levon 791f5207b7SJohn Levon state = get_state(my_id, name, sym); 801f5207b7SJohn Levon if (state) 811f5207b7SJohn Levon return state; 821f5207b7SJohn Levon 831f5207b7SJohn Levon state = get_state(SMATCH_EXTRA, name, sym); 841f5207b7SJohn Levon if (state) 851f5207b7SJohn Levon return state; 861f5207b7SJohn Levon return alloc_estate_rl(alloc_whole_rl(get_real_base_type(sym))); 871f5207b7SJohn Levon } 881f5207b7SJohn Levon 891f5207b7SJohn Levon struct smatch_state *get_orig_estate_type(const char *name, struct symbol *sym, struct symbol *type) 901f5207b7SJohn Levon { 911f5207b7SJohn Levon struct smatch_state *state; 921f5207b7SJohn Levon 931f5207b7SJohn Levon state = get_state(my_id, name, sym); 941f5207b7SJohn Levon if (state) 951f5207b7SJohn Levon return state; 961f5207b7SJohn Levon 971f5207b7SJohn Levon state = get_state(SMATCH_EXTRA, name, sym); 981f5207b7SJohn Levon if (state) 991f5207b7SJohn Levon return state; 1001f5207b7SJohn Levon return alloc_estate_rl(alloc_whole_rl(type)); 1011f5207b7SJohn Levon } 1021f5207b7SJohn Levon 1031f5207b7SJohn Levon static struct range_list *generify_mtag_range(struct smatch_state *state) 1041f5207b7SJohn Levon { 1051f5207b7SJohn Levon struct range_list *rl; 1061f5207b7SJohn Levon struct data_range *drange; 1071f5207b7SJohn Levon 1081f5207b7SJohn Levon if (!estate_type(state) || estate_type(state)->type != SYM_PTR) 1091f5207b7SJohn Levon return estate_rl(state); 1101f5207b7SJohn Levon 1111f5207b7SJohn Levon /* 1121f5207b7SJohn Levon * The problem is that we get too specific on our param limits when we 1131f5207b7SJohn Levon * know exactly what pointers are passed to a function. It gets to the 1141f5207b7SJohn Levon * point where we say "pointer x will succeed, but everything else will 1151f5207b7SJohn Levon * fail." And then we introduce a new caller which passes a different 1161f5207b7SJohn Levon * pointer and it's like, "Sorry bro, that's not possible." 1171f5207b7SJohn Levon * 1181f5207b7SJohn Levon */ 119*c85f09ccSJohn Levon rl = estate_rl(state); 1201f5207b7SJohn Levon FOR_EACH_PTR(rl, drange) { 1211f5207b7SJohn Levon if (drange->min.value != drange->max.value) 1221f5207b7SJohn Levon continue; 123*c85f09ccSJohn Levon if (drange->min.value == 0) 124*c85f09ccSJohn Levon continue; 125*c85f09ccSJohn Levon if (is_err_ptr(drange->min)) 1261f5207b7SJohn Levon continue; 1271f5207b7SJohn Levon return rl_union(valid_ptr_rl, rl); 1281f5207b7SJohn Levon } END_FOR_EACH_PTR(drange); 1291f5207b7SJohn Levon 1301f5207b7SJohn Levon return estate_rl(state); 1311f5207b7SJohn Levon } 1321f5207b7SJohn Levon 1331f5207b7SJohn Levon static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr) 1341f5207b7SJohn Levon { 1351f5207b7SJohn Levon struct smatch_state *state, *old; 1361f5207b7SJohn Levon struct sm_state *tmp; 1371f5207b7SJohn Levon struct range_list *rl; 1381f5207b7SJohn Levon const char *param_name; 1391f5207b7SJohn Levon int param; 1401f5207b7SJohn Levon 1411f5207b7SJohn Levon FOR_EACH_MY_SM(SMATCH_EXTRA, __get_cur_stree(), tmp) { 1421f5207b7SJohn Levon param = get_param_num_from_sym(tmp->sym); 1431f5207b7SJohn Levon if (param < 0) 1441f5207b7SJohn Levon continue; 1451f5207b7SJohn Levon 1461f5207b7SJohn Levon param_name = get_param_name(tmp); 1471f5207b7SJohn Levon if (!param_name) 1481f5207b7SJohn Levon continue; 1491f5207b7SJohn Levon 1501f5207b7SJohn Levon state = __get_state(my_id, tmp->name, tmp->sym); 1511f5207b7SJohn Levon if (!state) 1521f5207b7SJohn Levon state = tmp->state; 1531f5207b7SJohn Levon 1541f5207b7SJohn Levon if (estate_is_whole(state) || estate_is_empty(state)) 1551f5207b7SJohn Levon continue; 1561f5207b7SJohn Levon old = get_state_stree(start_states, SMATCH_EXTRA, tmp->name, tmp->sym); 1571f5207b7SJohn Levon if (old && rl_equiv(estate_rl(old), estate_rl(state))) 1581f5207b7SJohn Levon continue; 1591f5207b7SJohn Levon 160efe51d0cSJohn Levon if (is_ignored_kernel_data(param_name)) 161efe51d0cSJohn Levon continue; 162efe51d0cSJohn Levon 1631f5207b7SJohn Levon rl = generify_mtag_range(state); 1641f5207b7SJohn Levon sql_insert_return_states(return_id, return_ranges, PARAM_LIMIT, 1651f5207b7SJohn Levon param, param_name, show_rl(rl)); 1661f5207b7SJohn Levon } END_FOR_EACH_SM(tmp); 1671f5207b7SJohn Levon } 1681f5207b7SJohn Levon 1691f5207b7SJohn Levon static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state) 1701f5207b7SJohn Levon { 1711f5207b7SJohn Levon struct smatch_state *orig_vals; 1721f5207b7SJohn Levon int param; 1731f5207b7SJohn Levon 1741f5207b7SJohn Levon param = get_param_num_from_sym(sym); 1751f5207b7SJohn Levon if (param < 0) 1761f5207b7SJohn Levon return; 1771f5207b7SJohn Levon 1781f5207b7SJohn Levon orig_vals = get_orig_estate_type(name, sym, estate_type(state)); 1791f5207b7SJohn Levon set_state(my_id, name, sym, orig_vals); 1801f5207b7SJohn Levon } 1811f5207b7SJohn Levon 1821f5207b7SJohn Levon static void match_save_states(struct expression *expr) 1831f5207b7SJohn Levon { 1841f5207b7SJohn Levon push_stree(&saved_stack, start_states); 1851f5207b7SJohn Levon start_states = NULL; 1861f5207b7SJohn Levon } 1871f5207b7SJohn Levon 1881f5207b7SJohn Levon static void match_restore_states(struct expression *expr) 1891f5207b7SJohn Levon { 1901f5207b7SJohn Levon free_stree(&start_states); 1911f5207b7SJohn Levon start_states = pop_stree(&saved_stack); 1921f5207b7SJohn Levon } 1931f5207b7SJohn Levon 1941f5207b7SJohn Levon void register_param_limit(int id) 1951f5207b7SJohn Levon { 1961f5207b7SJohn Levon my_id = id; 1971f5207b7SJohn Levon 198efe51d0cSJohn Levon set_dynamic_states(my_id); 1991f5207b7SJohn Levon add_hook(&save_start_states, AFTER_DEF_HOOK); 2001f5207b7SJohn Levon add_hook(&free_start_states, AFTER_FUNC_HOOK); 2011f5207b7SJohn Levon 2021f5207b7SJohn Levon add_extra_mod_hook(&extra_mod_hook); 2031f5207b7SJohn Levon add_unmatched_state_hook(my_id, &unmatched_state); 2041f5207b7SJohn Levon add_merge_hook(my_id, &merge_estates); 2051f5207b7SJohn Levon 2061f5207b7SJohn Levon add_hook(&match_save_states, INLINE_FN_START); 2071f5207b7SJohn Levon add_hook(&match_restore_states, INLINE_FN_END); 2081f5207b7SJohn Levon 2091f5207b7SJohn Levon add_split_return_callback(&print_return_value_param); 2101f5207b7SJohn Levon } 2111f5207b7SJohn Levon 212