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