1 /* 2 * Copyright (C) 2019 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 * The problem here is something like this: 20 * 21 * return (blah() || whatever()) ? NULL : some_function(); 22 * 23 * When we are parsing this what happens is that we first parse all the 24 * expressions "(blah() || whatever()) ? NULL : some_function();" and then 25 * we parse the return statement. 26 * 27 * When we parse the return statement, we say "Oh, this is a conditional. Let's 28 * get all the implications for true and false." But because 29 * "(blah() || whatever())" is a function pointer, that means there aren't any 30 * implications. 31 * 32 * So what this module does is it ties the implications to the expression 33 * pointer so that we can retreive them easily. It's similar to Smatch stored 34 * implications but it doesn't save condition, it saves the pointer. 35 * 36 * We ignore pre loop conditions which Smatch parses twice. 37 * 38 */ 39 40 #include "smatch.h" 41 #include "smatch_slist.h" 42 43 static int my_id; 44 45 STATE(true_path); 46 STATE(false_path); 47 48 void record_condition(struct expression *expr) 49 { 50 char name[32]; 51 sval_t val; 52 53 if (get_value(expr, &val)) 54 return; 55 56 if (__in_pre_condition) 57 return; 58 59 snprintf(name, sizeof(name), "condition %p", expr); 60 set_true_false_states(my_id, name, NULL, &true_path, &false_path); 61 } 62 63 void register_parsed_conditions(int id) 64 { 65 my_id = id; 66 add_hook(&record_condition, CONDITION_HOOK); 67 } 68 69 static void filter_by_sm(struct sm_state *sm, 70 struct state_list **true_stack, 71 struct state_list **false_stack) 72 { 73 if (!sm) 74 return; 75 76 if (sm->state == &true_path) 77 add_ptr_list(true_stack, sm); 78 else if (sm->state == &false_path) 79 add_ptr_list(false_stack, sm); 80 81 if (sm->merged) { 82 filter_by_sm(sm->left, true_stack, false_stack); 83 filter_by_sm(sm->right, true_stack, false_stack); 84 } 85 } 86 87 struct sm_state *parsed_condition_implication_hook(struct expression *expr, 88 struct state_list **true_stack, 89 struct state_list **false_stack) 90 { 91 struct state_list *tmp_true = NULL; 92 struct state_list *tmp_false = NULL; 93 struct sm_state *sm, *tmp; 94 char name[32]; 95 96 snprintf(name, sizeof(name), "condition %p", expr); 97 98 sm = get_sm_state(my_id, name, NULL); 99 if (!sm) 100 return NULL; 101 if (!sm->merged) 102 return NULL; 103 104 filter_by_sm(sm, &tmp_true, &tmp_false); 105 if (!tmp_true && !tmp_false) 106 return NULL; 107 108 FOR_EACH_PTR(tmp_true, tmp) { 109 add_ptr_list(true_stack, tmp); 110 } END_FOR_EACH_PTR(tmp); 111 112 FOR_EACH_PTR(tmp_false, tmp) { 113 add_ptr_list(false_stack, tmp); 114 } END_FOR_EACH_PTR(tmp); 115 116 free_slist(&tmp_true); 117 free_slist(&tmp_false); 118 119 return sm; 120 } 121