1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2015, 2017 The University of Utah
4 // All rights reserved.
5 //
6 // This file is part of `csmith', a random generator of C programs.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
10 //
11 //   * Redistributions of source code must retain the above copyright notice,
12 //     this list of conditions and the following disclaimer.
13 //
14 //   * Redistributions in binary form must reproduce the above copyright
15 //     notice, this list of conditions and the following disclaimer in the
16 //     documentation and/or other materials provided with the distribution.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 
30 #if HAVE_CONFIG_H
31 #  include <config.h>
32 #endif
33 
34 #ifdef WIN32
35 #pragma warning(disable : 4786)   /* Disable annoying warning messages */
36 #endif
37 
38 #include "FactMgr.h"
39 
40 #include <cassert>
41 #include <sstream>
42 #include <iostream>
43 #include <vector>
44 #include <map>
45 
46 #include "Fact.h"
47 #include "FactPointTo.h"
48 #include "FactUnion.h"
49 #include "Variable.h"
50 #include "Block.h"
51 #include "StatementFor.h"
52 #include "StatementIf.h"
53 #include "StatementReturn.h"
54 #include "StatementAssign.h"
55 #include "StatementExpr.h"
56 #include "StatementGoto.h"
57 #include "StatementArrayOp.h"
58 #include "Function.h"
59 #include "FunctionInvocation.h"
60 #include "FunctionInvocationUser.h"
61 #include "CGOptions.h"
62 #include "Expression.h"
63 #include "ExpressionVariable.h"
64 #include "Lhs.h"
65 #include "CFGEdge.h"
66 
67 using namespace std;
68 
69 std::vector<Fact*> FactMgr::meta_facts;
70 
71 void
add_new_var_fact_and_update_inout_maps(const Block * blk,const Variable * var)72 FactMgr::add_new_var_fact_and_update_inout_maps(const Block* blk, const Variable* var)
73 {
74 	if (blk == NULL) {
75 		assert(var->is_global());
76 	}
77 	// var is global if blk == 0, we add fact to all blocks of this function
78 	// otherwise, only add fact to blocks equal or below blk (variable is declared in blk)
79 	for (size_t i=0; i<FactMgr::meta_facts.size(); i++) {
80 		FactVec facts = FactMgr::meta_facts[i]->abstract_fact_for_var_init(var);
81 		for (size_t k=0; k<facts.size(); k++) {
82 			const Fact* f = facts[k];
83 			// sometimes the facts is already included during the creation of child
84 			// functions. so need this check
85 			if (find_related_fact(global_facts, f) == 0) {
86 				global_facts.push_back(f);
87 			}
88 
89 			map<const Statement*, FactVec>::iterator iter;
90 			for(iter = map_facts_in.begin(); iter != map_facts_in.end(); ++iter) {
91 				const Statement* stm = iter->first;
92 				if (stm && (stm->in_block(blk) || blk == NULL)) {
93 					iter->second.push_back(f);
94 				}
95 			}
96 			for(iter = map_facts_out.begin(); iter != map_facts_out.end(); ++iter) {
97 				const Statement* stm = iter->first;
98 				assert(stm);
99 				if (blk) {
100 					add_fact_out(stm, f);
101 				} else {
102 					iter->second.push_back(f);
103 				}
104 			}
105 		}
106 	}
107 }
108 
109 void
add_param_facts(const vector<const Expression * > & param_values,FactVec & facts)110 FactMgr::add_param_facts(const vector<const Expression*>& param_values, FactVec& facts)
111 {
112 	for (size_t i=0; i<func->param.size(); i++) {
113 		const Variable* var = func->param[i];
114 		const Expression* value = param_values[i];
115 		Lhs lhs(*var);
116 		FactMgr::update_fact_for_assign(&lhs, value, facts);
117 	}
118 }
119 
120 void
add_new_var_fact(const Variable * v,FactVec & facts)121 FactMgr::add_new_var_fact(const Variable* v, FactVec& facts)
122 {
123 	assert(v);
124 	for (size_t i=0; i<FactMgr::meta_facts.size(); i++) {
125 		FactVec tmp_facts = FactMgr::meta_facts[i]->abstract_fact_for_var_init(v);
126 		for (size_t k=0; k<tmp_facts.size(); k++) {
127 			const Fact* f = tmp_facts[k];
128 			// sometimes the facts is already included during the creation of child
129 			// functions. so need this check
130 			if (find_related_fact(facts, f) == 0) {
131 				facts.push_back(f);
132 			}
133 		}
134 	}
135 }
136 
137 /* update facts env for out-of-scope variables */
138 void
update_facts_for_oos_vars(const vector<Variable * > & vs,FactVec & facts)139 FactMgr::update_facts_for_oos_vars(const vector<Variable*>& vs, FactVec& facts)
140 {
141 	vector<const Variable*> vars;
142 	vars.insert(vars.end(), vs.begin(), vs.end());
143 	return update_facts_for_oos_vars(vars, facts);
144 }
145 
146 void
update_facts_for_oos_vars(const vector<const Variable * > & vars,FactVec & facts)147 FactMgr::update_facts_for_oos_vars(const vector<const Variable*>& vars, FactVec& facts)
148 {
149 	//print_facts(facts);
150 	size_t i, j;
151 	// remove all facts related to vars, as they become irrelevant going out of scope
152 	for (i=0; i<vars.size(); i++) {
153 		const Variable* var = vars[i];
154 		size_t len = facts.size();
155 		for (j=0; j<len; j++) {
156 			//print_facts(facts);
157 			// remove all facts related to this variable
158 			const Fact* f = facts[j];
159 			if (var->match(f->get_var())) {
160 				facts.erase(facts.begin() + j);
161 				len--;
162 				j--;
163 			}
164 		}
165 	}
166 	// mark any remaining facts that may point to a out-of-scope variable as "point to garbage"
167 	for (i=0; i<vars.size(); i++) {
168 		const Variable* var = vars[i];
169 		for (j=0; j<facts.size(); j++) {
170 			if (facts[j]->eCat == ePointTo) {
171 				FactPointTo* f = (FactPointTo*)(facts[j]);
172 				FactPointTo* new_fact = f->mark_dead_var(var);
173 				if (new_fact) {
174 					facts[j] = new_fact;
175 				}
176 			}
177 		}
178 	}
179 }
180 
181 /*
182  * remove facts concerning variables local to a function
183  * hint: relevant facts are those concerns variable visible at the end of this function
184  */
185 void
remove_function_local_facts(std::vector<const Fact * > & inputs,const Statement * stm)186 FactMgr::remove_function_local_facts(std::vector<const Fact*>& inputs, const Statement* stm)
187 {
188 	size_t i;
189 	size_t len = inputs.size();
190 	assert(stm->func);
191 	const Function* func = stm->func;
192 	// remove irrelevant facts
193 	for (i=0; i<len; i++) {
194 		const Variable* v = inputs[i]->get_var();
195 		// if it's fact for a local variable of this function, or return variable
196 		// of another function, we are not interested in them after exit function
197 		if (func->is_var_on_stack(v, stm) || (v->is_rv() && !func->rv->match(v))) {
198 			inputs.erase(inputs.begin() + i);
199 			i--;
200 			len--;
201 		}
202 	}
203 	// mark any remaining facts that may point to a local vars of this
204 	// function as "point to garbage"
205 	for (i=0; i<inputs.size(); i++) {
206 		if (inputs[i]->eCat == ePointTo) {
207 			FactPointTo* f = (FactPointTo*)(inputs[i]);
208 			FactPointTo* new_fact = f->mark_func_end(stm);
209 			if (new_fact) {
210 				inputs[i] = new_fact;
211 			}
212 		}
213 	}
214 }
215 
216 void
setup_in_out_maps(bool first_time)217 FactMgr::setup_in_out_maps(bool first_time)
218 {
219 	if (first_time) {
220 		// first time revisit, create map_facts_in_final and map_facts_out_final with cloned facts
221 		map<const Statement*, vector<const Fact*> >::const_iterator iter;
222 		for(iter = map_facts_in.begin(); iter != map_facts_in.end(); ++iter) {
223 			const Statement* stm = iter->first;
224 			const vector<const Fact*>& facts1 = iter->second;
225 			map_facts_in_final[stm] = copy_facts(facts1);
226 		}
227 		for(iter = map_facts_out.begin(); iter != map_facts_out.end(); ++iter) {
228 			const Statement* stm = iter->first;
229 			const vector<const Fact*>& facts1 = iter->second;
230 			map_facts_out_final[stm] = copy_facts(facts1);
231 		}
232 	}
233 	else {
234 		// not the 1st time revisit
235 		// combine facts_in and facts_out from this invocation with facts from previous invocations
236 		map<const Statement*, vector<Fact*> >::iterator iter;
237 		for(iter = map_facts_in_final.begin(); iter != map_facts_in_final.end(); ++iter) {
238 			const Statement* stm = iter->first;
239 			vector<Fact*>& facts1 = iter->second;
240 			const FactVec& facts2 = map_facts_in[stm];
241 			combine_facts(facts1, facts2);
242 		}
243 		for(iter = map_facts_out_final.begin(); iter != map_facts_out_final.end(); ++iter) {
244 			const Statement* stm = iter->first;
245 			vector<Fact*>& facts1 = iter->second;
246 			const FactVec& facts2 = map_facts_out[stm];
247 			combine_facts(facts1, facts2);
248 		}
249 	}
250 	//JYTODO: beef up the sanity check
251 	//sanity_check_map();
252 }
253 
254 void
set_fact_in(const Statement * s,const FactVec & facts)255 FactMgr::set_fact_in(const Statement* s, const FactVec& facts)
256 {
257 	map_facts_in[s] = facts;
258 }
259 
260 /*
261  * special treatment for "contine" and "break", their output env should has no facts
262  * of local variables in the loop. For return, there should be no fact for local varibles
263  * of the function
264  */
265 void
set_fact_out(const Statement * s,const FactVec & facts)266 FactMgr::set_fact_out(const Statement* s, const FactVec& facts)
267 {
268 	if (s->eType == eContinue || s->eType == eBreak) {
269 		FactVec facts_copy = facts;
270 		remove_loop_local_facts(s, facts_copy);
271 		map_facts_out[s] = facts_copy;
272 	}
273 	else if (s->eType == eGoto) {
274 		const StatementGoto* sg = dynamic_cast<const StatementGoto*>(s);
275 		FactVec facts_copy;
276 		FactMgr::update_facts_for_dest(facts, facts_copy, sg->dest);
277 		map_facts_out[s] = facts_copy;
278 	}
279 	else if (s->eType == eReturn || s->parent==NULL) {
280 		FactVec facts_copy = facts;
281 		remove_function_local_facts(facts_copy, s);
282 		map_facts_out[s] = facts_copy;
283 	}
284 	else {
285 		map_facts_out[s] = facts;
286 	}
287 }
288 
289 /*
290  * add a fact to facts_out of a statement, discard the fact
291  * if it becomes irrelevant at the end of this statement.
292  * such as local facts after return
293  */
294 void
add_fact_out(const Statement * stm,const Fact * fact)295 FactMgr::add_fact_out(const Statement* stm, const Fact* fact)
296 {
297 	const Variable* var = fact->get_var();
298 	if (func->is_var_visible(var, stm)) {
299 		if (stm->eType == eReturn && !var->is_global()) return;
300 		if (stm->eType == eBreak || stm->eType == eContinue) {
301 			Block* b;
302 			for (b=stm->parent; b && !b->looping; b=b->parent) {
303 				/* Empty. */
304 			}
305 			if (!func->is_var_visible(var, b)) {
306 				return;
307 			}
308 		}
309 		if (stm->eType == eGoto) {
310 			const StatementGoto* sg = (const StatementGoto*)stm;
311 			if (!func->is_var_visible(var, sg->dest)) {
312 				return;
313 			}
314 		}
315 		map_facts_out[stm].push_back(fact);
316 	}
317 }
318 
319 /*
320  * add:			parameter facts
321  * remove:		facts concerning local variables
322  * exception:	facts can be indirectly accessed through pointers
323  *				for example: { int i; func(&i)}. The facts of i will not be removed
324  */
325 void
caller_to_callee_handover(const FunctionInvocationUser * fiu,std::vector<const Fact * > & inputs)326 FactMgr::caller_to_callee_handover(const FunctionInvocationUser* fiu, std::vector<const Fact*>& inputs)
327 {
328 	// add parameter facts
329 	add_param_facts(fiu->param_value, inputs);
330 
331 	size_t i, j, cnt;
332 	std::vector<const Fact*> keep_facts;
333 	size_t len = inputs.size();
334 	// move global facts and parameter facts to a separate "keep" list
335 	for (i=0; i<len; i++) {
336 		const Variable* v = inputs[i]->get_var();
337 		if (v->is_global() || find_variable_in_set(func->param, v) >=0) {
338 			keep_facts.push_back(inputs[i]);
339 			inputs.erase(inputs.begin() + i);
340 			i--;
341 			len--;
342 		}
343 	}
344 	// find all the facts for variables that might be pointed to by variables we already found.
345 	// this include variables on stack (most likely locals of callers) but invisible to
346 	// this function
347 	do {
348 		cnt = keep_facts.size();
349 		for (i=0; i<len; i++) {
350 			const Fact* f = inputs[i];
351 			// const Variable* v = f->get_var();
352 			for (j=0; j<keep_facts.size(); j++) {
353 				if (keep_facts[j]->eCat == ePointTo) {
354 					const FactPointTo* fp = dynamic_cast<const FactPointTo*>(keep_facts[j]);
355 					if (fp->point_to(f->get_var())) {
356 						keep_facts.push_back(f);
357 						inputs.erase(inputs.begin() + i);
358 						i--;
359 						len--;
360 						break;
361 					}
362 				}
363 			}
364 		}
365 	} while (keep_facts.size() > cnt);
366 	inputs = keep_facts;
367 }
368 
369 /*
370  * remove facts related to return variables of other functions
371  */
remove_rv_facts(FactVec & facts)372 void FactMgr::remove_rv_facts(FactVec& facts)
373 {
374 	size_t len = facts.size();
375 	for (size_t i=0; i<len; i++) {
376 		const Fact* f = facts[i];
377 		if (f->get_var()->is_rv() && !func->rv->match(f->get_var())) {
378 			facts.erase(facts.begin() + i);
379 			len--;
380 			i--;
381 		}
382 	}
383 }
384 
385 bool
update_fact_for_assign(const Lhs * lhs,const Expression * rhs,FactVec & inputs)386 FactMgr::update_fact_for_assign(const Lhs* lhs, const Expression* rhs, FactVec& inputs)
387 {
388 	bool changed = false;
389     for (size_t i=0; i<FactMgr::meta_facts.size(); i++) {
390         vector<const Fact*> facts = FactMgr::meta_facts[i]->abstract_fact_for_assign(inputs, lhs, rhs);
391 		if (facts.size() == 1 && !facts[0]->get_var()->isArray) {
392 			// for must-point-to fact concerning no-array variable, just renew the old fact
393 			renew_fact(inputs, facts[0]);
394 		}
395 		else {
396 			// for may-point-to facts (which means pointer on LHS is uncertain), merge them with old facts
397 			for (size_t j=0; j<facts.size(); j++) {
398 				const Fact* f = facts[j];
399 				merge_fact(inputs, f);
400 			}
401 		}
402 		if (facts.size() > 0) {
403 			changed = true;
404 		}
405     }
406 	return changed;
407 }
408 
409 bool
update_fact_for_assign(const StatementAssign * sa,FactVec & inputs)410 FactMgr::update_fact_for_assign(const StatementAssign* sa, FactVec& inputs)
411 {
412 	if (FactMgr::update_fact_for_assign(sa->get_lhs(), sa->get_rhs(), inputs)) {
413 		sa->func->fact_changed = true;
414 		return true;
415     }
416 	return false;
417 }
418 
419 void
update_fact_for_return(const StatementReturn * sr,FactVec & inputs)420 FactMgr::update_fact_for_return(const StatementReturn* sr, FactVec& inputs)
421 {
422 	size_t i, j;
423     for (i=0; i<FactMgr::meta_facts.size(); i++) {
424         std::vector<const Fact*> facts = FactMgr::meta_facts[i]->abstract_fact_for_return(inputs, sr->get_var(), sr->func);
425 		for (j=0; j<facts.size(); j++) {
426 			// merge with other return statements
427 			if (merge_fact(inputs, facts[j])) {
428 				sr->func->fact_changed = true;
429 			}
430 		}
431     }
432 	// incorporate current facts into return facts
433 	FactMgr* fm = get_fact_mgr_for_func(sr->func);
434 	fm->set_fact_out(sr, inputs);
435 }
436 
437 void
update_facts_for_dest(const FactVec & facts_in,FactVec & facts_out,const Statement * dest)438 FactMgr::update_facts_for_dest(const FactVec& facts_in, FactVec& facts_out, const Statement* dest)
439 {
440 	size_t i, j;
441 	vector<const Variable*> oos_vars;
442 	const Function* func = dest->func;
443 	assert(func);
444 	// find all the variales that are out-of-scope after jump to destination
445 	// oos variables are those not on stack and not global
446 	for (i=0; i<facts_in.size(); i++) {
447 		const Fact* f = facts_in[i];
448 		const Variable* var = f->get_var();
449 		// return variable, target site don't need them
450 		if (!var || var->is_rv()) continue;
451 		if (func->is_var_oos(var, dest)) {
452 			if (find_variable_in_set(oos_vars, var) == -1) {
453 				oos_vars.push_back(var);
454 			}
455 		}
456 		if (f->eCat == ePointTo) {
457 			const FactPointTo* fp = dynamic_cast<const FactPointTo*>(f);
458 			for (j=0; j<fp->get_point_to_vars().size(); j++) {
459 				const Variable* v = fp->get_point_to_vars()[j];
460 				if (!FactPointTo::is_special_ptr(v) && func->is_var_oos(v, dest)) {
461 					if (find_variable_in_set(oos_vars, v) == -1) {
462 						oos_vars.push_back(v);
463 					}
464 				}
465 			}
466 		}
467 		merge_fact(facts_out, f);
468 	}
469 	FactMgr::update_facts_for_oos_vars(oos_vars, facts_out);
470 }
471 
472 ///////////////////////////////////////////////////////////////////////////////
473 
474 /*
475  *
476  */
FactMgr(const Function * f)477 FactMgr::FactMgr(const Function* f)
478 : func(f)
479 {
480 }
481 
482 /*
483  *
484  */
~FactMgr(void)485 FactMgr::~FactMgr(void)
486 {
487 	size_t i;
488 	for (i=0; i<cfg_edges.size(); i++) {
489 		delete cfg_edges[i];
490 	}
491 	cfg_edges.clear();
492 }
493 
494 void
add_interested_facts(int interests)495 FactMgr::add_interested_facts(int interests)
496 {
497  	// create meta facts for subsequent iterations
498     if (interests & ePointTo) {
499         //meta_facts.push_back(new FactPointTo(0));
500         //meta_facts.push_back(FactPointTo::make_fact(0));
501         FactPointTo *fp = FactPointTo::make_fact(0);
502         meta_facts.push_back(fp);
503 	}
504 	if (interests & eUnionWrite) {
505 		FactUnion *fu = FactUnion::make_fact(0, 0);
506 		meta_facts.push_back(fu);
507     }
508 }
509 
510 void
restore_facts(vector<const Fact * > & old_facts)511 FactMgr::restore_facts(vector<const Fact*>& old_facts)
512 {
513 	makeup_new_var_facts(old_facts, global_facts);
514 	global_facts = old_facts;
515 }
516 
517 void
makeup_new_var_facts(vector<const Fact * > & old_facts,const vector<const Fact * > & new_facts)518 FactMgr::makeup_new_var_facts(vector<const Fact*>& old_facts, const vector<const Fact*>& new_facts)
519 {
520     size_t i;
521     for (i=0; i<new_facts.size(); i++) {
522 		const Fact* f = new_facts[i];
523 		const Variable* v = f->get_var();
524 		if (v->is_global() || v->is_local()) {
525 			// if there are variable facts not present in old facts,
526 			// mean they are variables created after old_facts,
527 			// manually add them
528 			if (find_related_fact(old_facts, f) == 0) {
529 				FactMgr::add_new_var_fact(v, old_facts);
530 			}
531 		}
532 	}
533 }
534 
535 void
clear_map_visited(void)536 FactMgr::clear_map_visited(void)
537 {
538 	map<const Statement*, bool>::iterator iter;
539 	for(iter = map_visited.begin(); iter != map_visited.end(); ++iter) {
540 		iter->second = false;
541 	}
542 }
543 
544 void
backup_stm_fact_maps(const Statement * stm,map<const Statement *,FactVec> & facts_in,map<const Statement *,FactVec> & facts_out)545 FactMgr::backup_stm_fact_maps(const Statement* stm, map<const Statement*, FactVec>& facts_in, map<const Statement*, FactVec>& facts_out)
546 {
547 	vector<const Block*> blks;
548 	stm->get_blocks(blks);
549 	for (size_t i=0; i<blks.size(); i++) {
550 		const Block* b = blks[i];
551 		facts_in[b] = map_facts_in[b];
552 		facts_out[b] = map_facts_out[b];
553 		for (size_t j=0; j<b->stms.size(); j++) {
554 			backup_stm_fact_maps(b->stms[j], facts_in, facts_out);
555 		}
556 	}
557 	facts_in[stm] = map_facts_in[stm];
558 	facts_out[stm] = map_facts_out[stm];
559 }
560 
561 void
restore_stm_fact_maps(const Statement * stm,map<const Statement *,FactVec> & facts_in,map<const Statement *,FactVec> & facts_out)562 FactMgr::restore_stm_fact_maps(const Statement* stm, map<const Statement*, FactVec>& facts_in, map<const Statement*, FactVec>& facts_out)
563 {
564 	vector<const Block*> blks;
565 	stm->get_blocks(blks);
566 	for (size_t i=0; i<blks.size(); i++) {
567 		const Block* b = blks[i];
568 		map_facts_in[b] = facts_in[b];
569 		map_facts_out[b] = facts_out[b];
570 		for (size_t j=0; j<b->stms.size(); j++) {
571 			restore_stm_fact_maps(b->stms[j], facts_in, facts_out);
572 		}
573 	}
574 	map_facts_in[stm] = facts_in[stm];
575 	map_facts_out[stm] = facts_out[stm];
576 }
577 
578 /*
579  * reset input/output env of this statement and all statements included to empty
580  */
581 void
reset_stm_fact_maps(const Statement * stm)582 FactMgr::reset_stm_fact_maps(const Statement* stm)
583 {
584 	FactVec empty;
585 	vector<const Block*> blks;
586 	stm->get_blocks(blks);
587 	for (size_t i=0; i<blks.size(); i++) {
588 		const Block* b = blks[i];
589 		map_facts_in[b] = empty;
590 		map_facts_out[b] = empty;
591 		for (size_t j=0; j<b->stms.size(); j++) {
592 			reset_stm_fact_maps(b->stms[j]);
593 		}
594 	}
595 	map_facts_in[stm] = empty;
596 	map_facts_out[stm] = empty;
597 }
598 
599 bool
merge_jump_facts(FactVec & facts,const FactVec & jump_facts)600 FactMgr::merge_jump_facts(FactVec& facts, const FactVec& jump_facts)
601 {
602     size_t i;
603     bool changed = false;
604     for (i=0; i<facts.size(); i++) {
605 		const Fact* f = facts[i];
606 		if (!f->get_var()->is_rv()) {
607 			const Fact* jump_f = find_related_fact(jump_facts, f);
608 			// this should not happen: jump over initializers
609 			if (jump_f == 0) {
610 				if (f->eCat == ePointTo) {
611 					jump_f = FactPointTo::make_fact(f->get_var(), FactPointTo::garbage_ptr);
612 				}
613 				else if (f->eCat == eUnionWrite) {
614 					jump_f = FactUnion::make_fact(f->get_var(), FactUnion::BOTTOM);
615 				}
616 			}
617 			if (jump_f && merge_fact(facts, jump_f)) {
618 				changed = true;
619 			}
620 		}
621     }
622     return changed;
623 }
624 
625 /*
626  * create a control flow graph edge introduced by break/continue/goto
627  */
628 void
create_cfg_edge(const Statement * src,const Statement * dest,bool post_dest,bool is_back_link)629 FactMgr::create_cfg_edge(const Statement* src, const Statement* dest, bool post_dest, bool is_back_link)
630 {
631 	CFGEdge* edge = new CFGEdge(src, dest, post_dest, is_back_link);
632 	cfg_edges.push_back(edge);
633 }
634 
635 void
remove_loop_local_facts(const Statement * s,FactVec & facts)636 FactMgr::remove_loop_local_facts(const Statement* s, FactVec& facts)
637 {
638 	// filter out out-of-scope facts
639 	const Block* b = (s->eType==eBlock) ? (const Block*)s : s->parent;
640 	vector<Variable*> local_vars = b->local_vars;
641 	while (b && !b->looping) {
642 		b = b->parent;
643 		local_vars.insert(local_vars.end(), b->local_vars.begin(), b->local_vars.end());
644 	}
645 	FactMgr::update_facts_for_oos_vars(local_vars, facts);
646 }
647 
648 void
output_assertions(std::ostream & out,const Statement * stm,int indent,bool post_condition)649 FactMgr::output_assertions(std::ostream &out, const Statement* stm, int indent, bool post_condition)
650 {
651 	vector<Fact*> facts;
652 	if (!post_condition) {
653 		facts = map_facts_in_final[stm];
654 	} else {
655 		find_updated_final_facts(stm, facts);
656 	}
657 	if (facts.empty()) return;
658 
659 	if (stm->eType == eFor || stm->eType == eIfElse) {
660 		output_tab(out, indent);
661 		std::ostringstream ss;
662 		ss << "facts after " << (stm->eType == eFor ? "for loop" : "branching");
663 		output_comment_line(out, ss.str());
664 	}
665 	if (stm->eType == eAssign || stm->eType == eInvoke || stm->eType == eReturn) {
666 		output_tab(out, indent);
667 		std::ostringstream ss;
668 		ss << "statement id: " << stm->stm_id;
669 		output_comment_line(out, ss.str());
670 	}
671 	for (size_t i=0; i<facts.size(); i++) {
672 		const Fact* f = facts[i];
673 		const Effect& eff = func->feffect;
674 		const Variable* v = f->get_var();
675 		assert(v);
676 		// don't print facts regarding global variables that are neither read or written in this function
677 		if (v->is_global() && !eff.is_read(v) && !eff.is_written(v)) {
678 			continue;
679 		}
680 		output_tab(out, indent);
681 		f->OutputAssertion(out, stm);
682 	}
683 }
684 
685 void
find_updated_facts(const Statement * stm,vector<const Fact * > & facts)686 FactMgr::find_updated_facts(const Statement* stm, vector<const Fact*>& facts)
687 {
688 	const FactVec& facts_in = map_facts_in[stm];
689 	const FactVec& facts_out = map_facts_out[stm];
690 
691 	for (size_t i=0; i<facts_out.size(); i++) {
692 		const Fact* f = facts_out[i];
693 		const Fact* prev_f = find_related_fact(facts_in, f);
694 		assert(prev_f);
695 		if (!f->equal(*prev_f)) {
696 			facts.push_back(f);
697 		}
698 	}
699 }
700 
701 void
find_updated_final_facts(const Statement * stm,vector<Fact * > & facts)702 FactMgr::find_updated_final_facts(const Statement* stm, vector<Fact*>& facts)
703 {
704 	vector<Fact*>& facts_in = map_facts_in_final[stm];
705 	vector<Fact*>& facts_out = map_facts_out_final[stm];
706 
707 	for (size_t i=0; i<facts_out.size(); i++) {
708 		Fact* f = facts_out[i];
709 		// sometimes there is no pre-facts for return variables, so we don't
710 		// check the difference
711 		if (func->rv->match(f->get_var())) {
712 			facts.push_back(f);
713 		}
714 		else {
715 			const Fact* prev_f = find_related_fact(facts_in, f);
716 			assert(prev_f);
717 			if (!f->equal(*prev_f)) {
718 				facts.push_back(f);
719 			}
720 		}
721 	}
722 }
723 
724 void
find_dangling_global_ptrs(Function * f)725 FactMgr::find_dangling_global_ptrs(Function* f)
726 {
727 	for (size_t i=0; i<global_facts.size(); i++) {
728 		if (global_facts[i]->eCat == ePointTo) {
729 			FactPointTo* fp = (FactPointTo*)(global_facts[i]);
730 			const Variable* v = fp->get_var();
731 			// const pointers should never be dangling
732 			if (v->is_const() || !v->is_global()) continue;
733 			if (fp->is_dead()) {
734 				f->dead_globals.push_back(v);
735 			}
736 		}
737 	}
738 }
739 
740 void
sanity_check_map() const741 FactMgr::sanity_check_map() const
742 {
743 	map<const Statement*, vector<const Fact*> >::const_iterator iter;
744 	for(iter = map_facts_in.begin(); iter != map_facts_in.end(); ++iter) {
745 		const Statement* stm = iter->first;
746 		const vector<const Fact*>& facts = iter->second;
747 		for (size_t i=0; i<facts.size(); i++) {
748 			const Variable* v = facts[i]->get_var();
749 			if (!v->is_visible(stm->parent)) {
750 				// exception: the input facts to a function body could include the parameter facts
751 				if (stm->parent == 0 && find_variable_in_set(func->param, v) != -1) {
752 					continue;
753 				}
754 				//assert(0);
755 			}
756 		}
757 	}
758 
759 	for(iter = map_facts_out.begin(); iter != map_facts_out.end(); ++iter) {
760 		const Statement* stm = iter->first;
761 		const vector<const Fact*>& facts = iter->second;
762 		for (size_t i=0; i<facts.size(); i++) {
763 			const Variable* v = facts[i]->get_var();
764 			if (!v->is_visible(stm->parent) && !func->rv->match(v)) {
765 				//assert(0);
766 			}
767 		}
768 	}
769 }
770 
771 const vector<const Fact*>&
get_program_end_facts(void)772 FactMgr::get_program_end_facts(void)
773 {
774 	FactMgr* fm = get_fact_mgr_for_func(GetFirstFunction());
775 	return fm->global_facts;
776 }
777 
778 void
doFinalization()779 FactMgr::doFinalization()
780 {
781 	Fact::doFinalization();
782 	meta_facts.clear();
783 }
784 
785 ///////////////////////////////////////////////////////////////////////////////
786 
787 // Local Variables:
788 // c-basic-offset: 4
789 // tab-width: 4
790 // End:
791 
792 // End of file.
793