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