1*5a0e240fSJohn Levon /*
2*5a0e240fSJohn Levon  * Copyright (C) 2019 Oracle.
3*5a0e240fSJohn Levon  *
4*5a0e240fSJohn Levon  * This program is free software; you can redistribute it and/or
5*5a0e240fSJohn Levon  * modify it under the terms of the GNU General Public License
6*5a0e240fSJohn Levon  * as published by the Free Software Foundation; either version 2
7*5a0e240fSJohn Levon  * of the License, or (at your option) any later version.
8*5a0e240fSJohn Levon  *
9*5a0e240fSJohn Levon  * This program is distributed in the hope that it will be useful,
10*5a0e240fSJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*5a0e240fSJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*5a0e240fSJohn Levon  * GNU General Public License for more details.
13*5a0e240fSJohn Levon  *
14*5a0e240fSJohn Levon  * You should have received a copy of the GNU General Public License
15*5a0e240fSJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16*5a0e240fSJohn Levon  */
17*5a0e240fSJohn Levon 
18*5a0e240fSJohn Levon /*
19*5a0e240fSJohn Levon  * The problem here is something like this:
20*5a0e240fSJohn Levon  *
21*5a0e240fSJohn Levon  * return (blah() || whatever()) ? NULL : some_function();
22*5a0e240fSJohn Levon  *
23*5a0e240fSJohn Levon  * When we are parsing this what happens is that we first parse all the
24*5a0e240fSJohn Levon  * expressions "(blah() || whatever()) ? NULL : some_function();" and then
25*5a0e240fSJohn Levon  * we parse the return statement.
26*5a0e240fSJohn Levon  *
27*5a0e240fSJohn Levon  * When we parse the return statement, we say "Oh, this is a conditional.  Let's
28*5a0e240fSJohn Levon  * get all the implications for true and false."  But because
29*5a0e240fSJohn Levon  * "(blah() || whatever())" is a function pointer, that means there aren't any
30*5a0e240fSJohn Levon  * implications.
31*5a0e240fSJohn Levon  *
32*5a0e240fSJohn Levon  * So what this module does is it ties the implications to the expression
33*5a0e240fSJohn Levon  * pointer so that we can retreive them easily.  It's similar to Smatch stored
34*5a0e240fSJohn Levon  * implications but it doesn't save condition, it saves the pointer.
35*5a0e240fSJohn Levon  *
36*5a0e240fSJohn Levon  * We ignore pre loop conditions which Smatch parses twice.
37*5a0e240fSJohn Levon  *
38*5a0e240fSJohn Levon  */
39*5a0e240fSJohn Levon 
40*5a0e240fSJohn Levon #include "smatch.h"
41*5a0e240fSJohn Levon #include "smatch_slist.h"
42*5a0e240fSJohn Levon 
43*5a0e240fSJohn Levon static int my_id;
44*5a0e240fSJohn Levon 
45*5a0e240fSJohn Levon STATE(true_path);
46*5a0e240fSJohn Levon STATE(false_path);
47*5a0e240fSJohn Levon 
record_condition(struct expression * expr)48*5a0e240fSJohn Levon void record_condition(struct expression *expr)
49*5a0e240fSJohn Levon {
50*5a0e240fSJohn Levon 	char name[32];
51*5a0e240fSJohn Levon 	sval_t val;
52*5a0e240fSJohn Levon 
53*5a0e240fSJohn Levon 	if (get_value(expr, &val))
54*5a0e240fSJohn Levon 		return;
55*5a0e240fSJohn Levon 
56*5a0e240fSJohn Levon 	if (__in_pre_condition)
57*5a0e240fSJohn Levon 		return;
58*5a0e240fSJohn Levon 
59*5a0e240fSJohn Levon 	snprintf(name, sizeof(name), "condition %p", expr);
60*5a0e240fSJohn Levon 	set_true_false_states(my_id, name, NULL, &true_path, &false_path);
61*5a0e240fSJohn Levon }
62*5a0e240fSJohn Levon 
register_parsed_conditions(int id)63*5a0e240fSJohn Levon void register_parsed_conditions(int id)
64*5a0e240fSJohn Levon {
65*5a0e240fSJohn Levon 	my_id = id;
66*5a0e240fSJohn Levon 	add_hook(&record_condition, CONDITION_HOOK);
67*5a0e240fSJohn Levon }
68*5a0e240fSJohn Levon 
filter_by_sm(struct sm_state * sm,struct state_list ** true_stack,struct state_list ** false_stack)69*5a0e240fSJohn Levon static void filter_by_sm(struct sm_state *sm,
70*5a0e240fSJohn Levon 		       struct state_list **true_stack,
71*5a0e240fSJohn Levon 		       struct state_list **false_stack)
72*5a0e240fSJohn Levon {
73*5a0e240fSJohn Levon 	if (!sm)
74*5a0e240fSJohn Levon 		return;
75*5a0e240fSJohn Levon 
76*5a0e240fSJohn Levon 	if (sm->state == &true_path)
77*5a0e240fSJohn Levon 		add_ptr_list(true_stack, sm);
78*5a0e240fSJohn Levon 	else if (sm->state == &false_path)
79*5a0e240fSJohn Levon 		add_ptr_list(false_stack, sm);
80*5a0e240fSJohn Levon 
81*5a0e240fSJohn Levon 	if (sm->merged) {
82*5a0e240fSJohn Levon 		filter_by_sm(sm->left, true_stack, false_stack);
83*5a0e240fSJohn Levon 		filter_by_sm(sm->right, true_stack, false_stack);
84*5a0e240fSJohn Levon 	}
85*5a0e240fSJohn Levon }
86*5a0e240fSJohn Levon 
parsed_condition_implication_hook(struct expression * expr,struct state_list ** true_stack,struct state_list ** false_stack)87*5a0e240fSJohn Levon struct sm_state *parsed_condition_implication_hook(struct expression *expr,
88*5a0e240fSJohn Levon 				struct state_list **true_stack,
89*5a0e240fSJohn Levon 				struct state_list **false_stack)
90*5a0e240fSJohn Levon {
91*5a0e240fSJohn Levon 	struct state_list *tmp_true = NULL;
92*5a0e240fSJohn Levon 	struct state_list *tmp_false = NULL;
93*5a0e240fSJohn Levon 	struct sm_state *sm, *tmp;
94*5a0e240fSJohn Levon 	char name[32];
95*5a0e240fSJohn Levon 
96*5a0e240fSJohn Levon 	snprintf(name, sizeof(name), "condition %p", expr);
97*5a0e240fSJohn Levon 
98*5a0e240fSJohn Levon 	sm = get_sm_state(my_id, name, NULL);
99*5a0e240fSJohn Levon 	if (!sm)
100*5a0e240fSJohn Levon 		return NULL;
101*5a0e240fSJohn Levon 	if (!sm->merged)
102*5a0e240fSJohn Levon 		return NULL;
103*5a0e240fSJohn Levon 
104*5a0e240fSJohn Levon 	filter_by_sm(sm, &tmp_true, &tmp_false);
105*5a0e240fSJohn Levon 	if (!tmp_true && !tmp_false)
106*5a0e240fSJohn Levon 		return NULL;
107*5a0e240fSJohn Levon 
108*5a0e240fSJohn Levon 	FOR_EACH_PTR(tmp_true, tmp) {
109*5a0e240fSJohn Levon 		add_ptr_list(true_stack, tmp);
110*5a0e240fSJohn Levon 	} END_FOR_EACH_PTR(tmp);
111*5a0e240fSJohn Levon 
112*5a0e240fSJohn Levon 	FOR_EACH_PTR(tmp_false, tmp) {
113*5a0e240fSJohn Levon 		add_ptr_list(false_stack, tmp);
114*5a0e240fSJohn Levon 	} END_FOR_EACH_PTR(tmp);
115*5a0e240fSJohn Levon 
116*5a0e240fSJohn Levon 	free_slist(&tmp_true);
117*5a0e240fSJohn Levon 	free_slist(&tmp_false);
118*5a0e240fSJohn Levon 
119*5a0e240fSJohn Levon 	return sm;
120*5a0e240fSJohn Levon }
121*5a0e240fSJohn Levon 
122