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
record_condition(struct expression * expr)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
register_parsed_conditions(int id)63 void register_parsed_conditions(int id)
64 {
65 my_id = id;
66 add_hook(&record_condition, CONDITION_HOOK);
67 }
68
filter_by_sm(struct sm_state * sm,struct state_list ** true_stack,struct state_list ** false_stack)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
parsed_condition_implication_hook(struct expression * expr,struct state_list ** true_stack,struct state_list ** false_stack)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
122