1 /*
2  * Copyright (C) 2014 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  * Some helper functions for managing links.
20  *
21  */
22 
23 #include "smatch.h"
24 #include "smatch_slist.h"
25 
alloc_link(struct var_sym_list * links)26 static struct smatch_state *alloc_link(struct var_sym_list *links)
27 {
28 	struct smatch_state *state;
29 	static char buf[256];
30 	struct var_sym *tmp;
31 	int i;
32 
33 	state = __alloc_smatch_state(0);
34 
35 	i = 0;
36 	FOR_EACH_PTR(links, tmp) {
37 		if (!i++) {
38 			snprintf(buf, sizeof(buf), "%s", tmp->var);
39 		} else {
40 			append(buf, ", ", sizeof(buf));
41 			append(buf, tmp->var, sizeof(buf));
42 		}
43 	} END_FOR_EACH_PTR(tmp);
44 
45 	state->name = alloc_sname(buf);
46 	state->data = links;
47 	return state;
48 }
49 
merge_link_states(struct smatch_state * s1,struct smatch_state * s2)50 struct smatch_state *merge_link_states(struct smatch_state *s1, struct smatch_state *s2)
51 {
52 	struct var_sym_list *new_links;
53 
54 	if (s1 == &undefined)
55 		return s2;
56 	if (s2 == &undefined)
57 		return s1;
58 
59 	if (var_sym_lists_equiv(s1->data, s2->data))
60 		return s1;
61 
62 	new_links = clone_var_sym_list(s1->data);
63 	merge_var_sym_list(&new_links, s2->data);
64 
65 	return alloc_link(new_links);
66 }
67 
store_link(int link_id,const char * var,struct symbol * sym,const char * link_name,struct symbol * link_sym)68 void store_link(int link_id, const char *var, struct symbol *sym, const char *link_name, struct symbol *link_sym)
69 {
70 
71 	struct smatch_state *old_state;
72 	struct var_sym_list *links;
73 
74 	if (!cur_func_sym)
75 		return;
76 
77 	old_state = get_state(link_id, var, sym);
78 	if (old_state)
79 		links = clone_var_sym_list(old_state->data);
80 	else
81 		links = NULL;
82 
83 	add_var_sym(&links, link_name, link_sym);
84 	set_state(link_id, var, sym, alloc_link(links));
85 }
86 
match_link_modify(struct sm_state * sm,struct expression * mod_expr)87 static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
88 {
89 	struct var_sym_list *links;
90 	struct var_sym *tmp;
91 
92 	links = sm->state->data;
93 
94 	FOR_EACH_PTR(links, tmp) {
95 		set_state(sm->owner - 1, tmp->var, tmp->sym, &undefined);
96 	} END_FOR_EACH_PTR(tmp);
97 	set_state(sm->owner, sm->name, sm->sym, &undefined);
98 }
99 
set_up_link_functions(int id,int link_id)100 void set_up_link_functions(int id, int link_id)
101 {
102 	if (id + 1 != link_id)
103 		sm_fatal("FATAL ERROR: links need to be registered directly after the check");
104 
105 	set_dynamic_states(link_id);
106 	add_merge_hook(link_id, &merge_link_states);
107 	add_modification_hook(link_id, &match_link_modify);
108 	// free link at the end of function
109 }
110 
111