From 3b31bff0ab2625dece9375939f187081f95f7554 Mon Sep 17 00:00:00 2001 From: Xuejun Yang Date: Thu, 16 Jun 2011 21:23:09 -0600 Subject: [PATCH] expand the data-flow analysis framework to union field analysis 1) add another type of fact, the union field that is last written into, to the framework 2) use this kind of fact to avoid reading padding bits of union fields (an unspecified value) 3) cleanup and streamline the current framework so that more type of facts can be analyzed with less trouble in the future 4) extend the effect analysis to union variables 5) increase the chance of having more struct and unions, and the chance of having struct and char* as union field 5) fix some gcc warnings 6) remove some unused code, rename some functions to more meaningful names 7) make code more debugable --- src/Block.cpp | 15 +- src/Block.h | 3 +- src/CGContext.cpp | 4 + src/CGOptions.cpp | 2 +- src/Effect.cpp | 21 ++- src/Effect.h | 1 + src/Expression.cpp | 18 +- src/ExpressionVariable.cpp | 6 +- src/Fact.cpp | 31 +++- src/Fact.h | 35 ++-- src/FactMgr.cpp | 211 ++++++++++++------------ src/FactMgr.h | 7 +- src/FactPointTo.cpp | 81 +++------ src/FactPointTo.h | 17 +- src/FactUnion.cpp | 292 +++++++++++++++++++++++++++++++++ src/FactUnion.h | 108 ++++++++++++ src/Function.cpp | 21 +-- src/Function.h | 1 + src/FunctionInvocation.cpp | 6 +- src/FunctionInvocationUser.cpp | 20 ++- src/FunctionInvocationUser.h | 6 +- src/Statement.cpp | 65 ++------ src/Statement.h | 2 +- src/StatementArrayOp.cpp | 10 +- src/StatementArrayOp.h | 4 +- src/StatementAssign.cpp | 17 +- src/StatementAssign.h | 4 +- src/StatementBreak.cpp | 8 +- src/StatementBreak.h | 2 +- src/StatementContinue.cpp | 8 +- src/StatementContinue.h | 2 +- src/StatementExpr.cpp | 8 +- src/StatementExpr.h | 2 +- src/StatementFor.cpp | 16 +- src/StatementFor.h | 3 +- src/StatementGoto.cpp | 25 +-- src/StatementGoto.h | 2 +- src/StatementIf.cpp | 8 +- src/StatementIf.h | 2 +- src/StatementReturn.cpp | 8 +- src/StatementReturn.h | 2 +- src/StringUtils.cpp | 9 + src/StringUtils.h | 2 + src/Type.cpp | 64 +++++--- src/Type.h | 1 + src/Variable.cpp | 24 ++- src/Variable.h | 3 + src/VariableSelector.cpp | 52 ++---- src/VariableSelector.h | 7 +- src/csmith.vcproj | 8 + 50 files changed, 843 insertions(+), 431 deletions(-) create mode 100644 src/FactUnion.cpp create mode 100644 src/FactUnion.h diff --git a/src/Block.cpp b/src/Block.cpp index abcd1ce21..cbbe98e5f 100644 --- a/src/Block.cpp +++ b/src/Block.cpp @@ -103,9 +103,8 @@ Block::make_random(CGContext &cg_context, bool looping) Function *curr_func = cg_context.get_current_func(); assert(curr_func); - Block *b = new Block(CGOptions::max_block_size()); + Block *b = new Block(cg_context.get_current_block(), CGOptions::max_block_size()); b->func = curr_func; - b->parent = cg_context.get_current_block(); b->looping = looping; // if there are induction variables, we are in a loop that traverses array(s) b->in_array_loop = !(cg_context.iv_bounds.empty()); @@ -129,6 +128,8 @@ Block::make_random(CGContext &cg_context, bool looping) return NULL; } unsigned int i; + if (b->stm_id == 1) + BREAK_NOP; // for debugging for (i = 0; i <= max; ++i) { Statement *s = Statement::make_random(cg_context); // In the exhaustive mode, Statement::make_random could return NULL; @@ -178,8 +179,8 @@ Block::make_random(CGContext &cg_context, bool looping) /* * */ -Block::Block(int block_size) - : Statement(eBlock), +Block::Block(Block* b, int block_size) + : Statement(eBlock, b), need_revisit(false), depth_protect(false), block_size_(block_size) @@ -503,7 +504,6 @@ bool Block::visit_facts(vector& inputs, CGContext& cg_context) const { int dummy; - //static int g = 0; FactMgr* fm = get_fact_mgr(&cg_context); vector dummy_facts; Effect pre_effect = cg_context.get_accum_effect(); @@ -556,6 +556,7 @@ Block::find_fixed_point(vector inputs, vector& post_fa FactMgr* fm = get_fact_mgr(&cg_context); // include outputs from all back edges leading to this block size_t i; + static int g = 0; vector edges; int cnt = 0; do { @@ -587,7 +588,9 @@ Block::find_fixed_point(vector inputs, vector& post_fa // revisit statements with new inputs for (i=0; ianalyze_with_edges_in(outputs, cg_context)) { fail_index = i; return false; diff --git a/src/Block.h b/src/Block.h index 066894805..6576b893a 100644 --- a/src/Block.h +++ b/src/Block.h @@ -64,8 +64,7 @@ class Block : public Statement // Factory method. static Block *make_random(CGContext &cg_context, bool looping = false); - - Block(int block_size); + Block(Block* b, int block_size); virtual ~Block(void); // diff --git a/src/CGContext.cpp b/src/CGContext.cpp index d258d0e64..d731aed5d 100644 --- a/src/CGContext.cpp +++ b/src/CGContext.cpp @@ -39,6 +39,7 @@ #include "Fact.h" #include "FactMgr.h" #include "FactPointTo.h" +#include "FactUnion.h" #include "Lhs.h" #include "Statement.h" #include "Bookkeeper.h" @@ -200,6 +201,9 @@ CGContext::read_var(const Variable *v) bool CGContext::check_read_var(const Variable *v, const std::vector& facts) { + if (v->is_union_field() && FactUnion::is_nonreadable_field(v, facts)) { + return false; + } if (!read_indices(v, facts)) { return false; } diff --git a/src/CGOptions.cpp b/src/CGOptions.cpp index e859fdf3c..f50390ed1 100644 --- a/src/CGOptions.cpp +++ b/src/CGOptions.cpp @@ -182,7 +182,7 @@ CGOptions::set_default_settings(void) max_exhaustive_depth(CGOPTIONS_DEFAULT_MAX_EXHAUSTIVE_DEPTH); max_indirect_level(CGOPTIONS_DEFAULT_MAX_INDIRECT_LEVEL); output_file(CGOPTIONS_DEFAULT_OUTPUT_FILE); - interested_facts(ePointTo); + interested_facts(ePointTo | eUnionWrite); allow_const_volatile(true); avoid_signed_overflow(true); CGOptions::paranoid(false); diff --git a/src/Effect.cpp b/src/Effect.cpp index 86bdd4fb2..9543fcda2 100644 --- a/src/Effect.cpp +++ b/src/Effect.cpp @@ -288,8 +288,11 @@ Effect::is_read(const Variable *v) const return true; } } - // if we read a struct/union, presumingly all the fields are read too - if (v->isFieldVarOf_) { + // if we read a struct, presumingly all the fields are read too + // however we can not say the same thing for unions: reading a particular + // unions field can cause unspecified behaviors, while reading the whole + // union won't + if (v->isFieldVarOf_ && v->isFieldVarOf_->type->eType == eStruct) { return is_read(v->isFieldVarOf_); } return false; @@ -605,6 +608,20 @@ Effect::has_global_effect(void) const return false; } +/* + * whether any field of an union is been read + */ +bool +Effect::union_field_is_read(void) const +{ + for (size_t i=0; iis_union_field()) { + return true; + } + } + return false; +} + /////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/src/Effect.h b/src/Effect.h index 2806a8e8b..c771a071f 100644 --- a/src/Effect.h +++ b/src/Effect.h @@ -69,6 +69,7 @@ class Effect bool sibling_field_is_written(const Variable *v) const; bool is_read_partially(const Variable* v) const; bool is_written_partially(const Variable* v) const; + bool union_field_is_read(void) const; bool has_race_with(const Effect &e) const; bool is_empty(void) const; void consolidate(void); diff --git a/src/Expression.cpp b/src/Expression.cpp index 03b2a32f0..337282a77 100644 --- a/src/Expression.cpp +++ b/src/Expression.cpp @@ -199,8 +199,8 @@ ParamExpressionFilter::filter(int v) const return true; } if (tt == eFunction) { - if (type_->eType == eStruct && !CGOptions::return_structs() || - type_->eType == eUnion && !CGOptions::return_unions()) + if ((type_->eType == eStruct && !CGOptions::return_structs()) || + (type_->eType == eUnion && !CGOptions::return_unions())) return true; } return false; @@ -228,20 +228,6 @@ ExpressionTypeProbability(const CGContext &cg_context, const ExpressionFilter *f return filter->number_to_termtype(i, Expression::exprTable_); } -/* - * - */ -static eTermType -ParameterTypeProbability(const CGContext &cg_context) -{ - if (cg_context.expr_depth > CGOptions::max_expr_depth()) - return eVariable; - - int i = rnd_upto(100); - ERROR_GUARD(MAX_TERM_TYPES); - return Expression::paramTable_->get_value(i); -} - unsigned int Expression::func_count(void) const { diff --git a/src/ExpressionVariable.cpp b/src/ExpressionVariable.cpp index ee54df1bc..ac9b09ba4 100644 --- a/src/ExpressionVariable.cpp +++ b/src/ExpressionVariable.cpp @@ -239,11 +239,7 @@ bool ExpressionVariable::visit_facts(vector& inputs, CGContext& cg_context) const { int deref_level = get_indirect_level(); - const Variable* v = get_var(); //->get_collective(); - // JYTODO: integrate this into get_collective? - // if (v->isFieldVarOf_ && v->is_array_field()) { - // v = v->isFieldVarOf_->get_collective(); - //} + const Variable* v = get_var(); if (deref_level > 0) { if (!FactPointTo::is_valid_ptr(v, inputs)) { return false; diff --git a/src/Fact.cpp b/src/Fact.cpp index e2d3713d9..e6b840233 100644 --- a/src/Fact.cpp +++ b/src/Fact.cpp @@ -33,6 +33,7 @@ #include "StatementReturn.h" using namespace std; +std::vector Fact::facts_; /////////////////////////////////////////////////////////////////////////////// @@ -40,8 +41,7 @@ using namespace std; * */ Fact::Fact(eFactCategory e) : - eCat(e), - no_more_update(false) + eCat(e) { // Nothing else to do. } @@ -54,6 +54,33 @@ Fact::~Fact(void) // Nothing else to do. } +/* + * output an assertion about the fact to check the correctness of compiler + * or generation time analysis + */ +void +Fact::OutputAssertion(std::ostream &out, const Statement* s) const +{ + if (!is_top()) { + if (s && !is_assertable(s)) { + out << "//"; + } + out << "assert ("; + Output(out); + out << ");" << endl; + } +} + +void +Fact::doFinalization() +{ + std::vector::iterator i; + for( i = facts_.begin(); i != facts_.end(); ++i) { + delete (*i); + } + facts_.clear(); +} + /////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/src/Fact.h b/src/Fact.h index a63e03eab..afa07e923 100644 --- a/src/Fact.h +++ b/src/Fact.h @@ -35,20 +35,19 @@ #include #include -enum eFactCategory { - eNullPtr=1, - eDeadPtr=2, - ePointTo=4, - //ePointToSize=4, - eIntRange=8, +enum eFactCategory { + ePointTo=1, + eUnionWrite=2, + /* todo + eIntRange=8, eEquality=16, eAlias=32, + */ }; +class Statement; class StatementAssign; class StatementReturn; -class Block; -class CGContext; class Variable; class Expression; class Lhs; @@ -70,17 +69,23 @@ class Fact virtual int join_visits(const Fact& fact) { return join(fact);} - virtual bool conflict_with(const Fact& /*fact*/) const { return false;}; + virtual bool imply(const Fact& /*fact*/) const = 0; - virtual bool is_related(const Fact& fact) const = 0; + // lattice functions + virtual bool is_top(void) const = 0; + virtual bool is_bottom(void) const = 0; + virtual void set_top(void) = 0; + virtual void set_bottom(void) = 0; + + virtual bool is_assertable(const Statement* s) const = 0; - virtual bool is_relevant(const Fact& ) const {return false;} + virtual bool is_related(const Fact& fact) const { return eCat == fact.eCat && get_var() == fact.get_var();} virtual bool equal(const Fact& fact) const { return this == &fact; }; virtual void Output(std::ostream &out) const = 0; - virtual void OutputAssertion(std::ostream &out) const = 0; + virtual void OutputAssertion(std::ostream &out, const Statement* s = NULL) const; virtual const Variable* get_var(void) const { return 0;}; @@ -88,9 +93,13 @@ class Fact virtual Fact* abstract_fact_for_return(const std::vector& /*facts*/, const ExpressionVariable* /*var*/, const Function* /*func*/) {return 0;}; + static void doFinalization(); + enum eFactCategory eCat; - bool no_more_update; +protected: + // keep track all created facts. used for releasing memory in doFinalization + static std::vector facts_; }; /////////////////////////////////////////////////////////////////////////////// diff --git a/src/FactMgr.cpp b/src/FactMgr.cpp index 274a41dd5..588d3e113 100644 --- a/src/FactMgr.cpp +++ b/src/FactMgr.cpp @@ -40,6 +40,7 @@ #include "Fact.h" #include "FactPointTo.h" +#include "FactUnion.h" #include "Variable.h" #include "Block.h" #include "StatementFor.h" @@ -62,42 +63,6 @@ using namespace std; std::vector FactMgr::meta_facts; -////////////////////////////////////////////////////////////////////////////// -/* check the incoming fact against existing fixed facts - return false if inviolation with fixed facts - ****************************************************************************/ -bool -FactMgr::validate_fact(const Fact* f, const FactVec& facts) -{ - for (size_t j=0; jconflict_with(*f)) { - //f->Output(cout); - return false; - } - } - return true; -} - -////////////////////////////////////////////////////////////////////////////// -/* check the incoming assignment against existing fixed facts - return false if inviolation with fixed facts - ****************************************************************************/ -bool -FactMgr::validate_assign(const Lhs* lhs, const Expression* e) -{ - /* canonize. todo: do this before this function call */ - for (size_t i=0; i facts = meta_facts[i]->abstract_fact_for_assign(global_facts, lhs, e); - for (size_t j=0; j& meta_facts = FactMgr::meta_facts; // TODO: consider facts related to struct or arrays - if (var->type->eType == eSimple || var->type->eType == ePointer) { + if (var->type->eType == eSimple || var->type->eType == ePointer || var->type->eType == eUnion) { FactVec facts; for (j=0; j& meta_facts = FactMgr::meta_facts; assert(v); // TODO: consider facts related to struct or arrays - if (v->type && (v->type->eType == eSimple || v->type->eType == ePointer) && v->init) { + if (v->type && (v->type->eType == eSimple || v->type->eType == ePointer || v->type->eType == eUnion) && v->init) { FactVec tmp_facts; for (j=0; jis_global()); - if (v->name == "g_8") + if (v->name == "g_39") j = 0; const vector& meta_facts = FactMgr::meta_facts; // TODO: consider facts related to struct or arrays - if (v->type->eType == eSimple || v->type->eType == ePointer) { + if (v->type->eType == eSimple || v->type->eType == ePointer || v->type->eType == eUnion) { FactVec facts; for (j=0; j& inputs, const Statement* s const Variable* v = inputs[i]->get_var(); // if it's fact for a local variable of this function, or return variable // of another function, we are not interested in them after exit function - if (func->is_var_on_stack(v, stm) || (v->type==0 && v != func->rv)) { + if (func->is_var_on_stack(v, stm) || (v->is_rv() && v != func->rv)) { inputs.erase(inputs.begin() + i); i--; len--; @@ -459,12 +424,15 @@ FactMgr::caller_to_callee_handover(const FunctionInvocationUser* fiu, std::vecto const Fact* f = inputs[i]; // const Variable* v = f->get_var(); for (j=0; jis_relevant(*f)) { - keep_facts.push_back(f); - inputs.erase(inputs.begin() + i); - i--; - len--; - break; + if (keep_facts[j]->eCat == ePointTo) { + const FactPointTo* fp = dynamic_cast(keep_facts[j]); + if (fp->point_to(f->get_var())) { + keep_facts.push_back(f); + inputs.erase(inputs.begin() + i); + i--; + len--; + break; + } } } } @@ -473,15 +441,14 @@ FactMgr::caller_to_callee_handover(const FunctionInvocationUser* fiu, std::vecto } /* - * remove facts related to return variables + * remove facts related to return variables of other functions */ void FactMgr::remove_rv_facts(FactVec& facts) { size_t len = facts.size(); for (size_t i=0; i return variable - if (f->get_var()->type == 0 && f->get_var() != func->rv) { + const Fact* f = facts[i]; + if (f->get_var()->is_rv() && f->get_var() != func->rv) { facts.erase(facts.begin() + i); len--; i--; @@ -552,15 +519,16 @@ update_facts_for_dest(const FactVec& facts_in, FactVec& facts_out, const Stateme // oos variables are those not on stack and not global for (i=0; i return variable, target site don't need them - if (f->get_var()->type == 0) continue; - if (f->eCat == ePointTo) { - const FactPointTo* fp = dynamic_cast(f); - if (func->is_var_oos(fp->get_var(), dest)) { - if (find_variable_in_set(oos_vars, fp->get_var()) == -1) { - oos_vars.push_back(fp->get_var()); - } + const Variable* var = f->get_var(); + // return variable, target site don't need them + if (!var || var->is_rv()) continue; + if (func->is_var_oos(var, dest)) { + if (find_variable_in_set(oos_vars, var) == -1) { + oos_vars.push_back(var); } + } + if (f->eCat == ePointTo) { + const FactPointTo* fp = dynamic_cast(f); for (j=0; jget_point_to_vars().size(); j++) { const Variable* v = fp->get_point_to_vars()[j]; if (!FactPointTo::is_special_ptr(v) && func->is_var_oos(v, dest)) { @@ -604,13 +572,13 @@ FactMgr::add_interested_facts(int interests) if (interests & ePointTo) { //meta_facts.push_back(new FactPointTo(0)); //meta_facts.push_back(FactPointTo::make_fact(0)); - FactPointTo *fact = FactPointTo::make_fact(0); - meta_facts.push_back(fact); + FactPointTo *fp = FactPointTo::make_fact(0); + meta_facts.push_back(fp); + } + if (interests & eUnionWrite) { + FactUnion *fu = FactUnion::make_fact(0, 0); + meta_facts.push_back(fu); } - //ePointToSize=4, - //eIntRange=8, - //eEquality=16, - //eAlias=32 } void @@ -757,7 +725,7 @@ merge_fact(FactVec& facts, const Fact* new_fact) for (i=0; iis_related(*new_fact)) { - if (f->conflict_with(*new_fact)) { + if (!f->imply(*new_fact)) { Fact* copy_fact = new_fact->clone(); copy_fact->join(*f); facts[i] = copy_fact; @@ -817,14 +785,19 @@ merge_jump_facts(FactVec& facts, const FactVec& jump_facts) size_t i; bool changed = false; for (i=0; i return variable, skip them - if (f->get_var()->type != 0) { + const Fact* f = facts[i]; + if (!f->get_var()->is_rv()) { const Fact* jump_f = find_related_fact(jump_facts, f); + // this should not happen: jump over initializers if (jump_f == 0) { - jump_f = FactPointTo::make_fact(f->get_var(), FactPointTo::garbage_ptr); + if (f->eCat == ePointTo) { + jump_f = FactPointTo::make_fact(f->get_var(), FactPointTo::garbage_ptr); + } + else if (f->eCat == eUnionWrite) { + jump_f = FactUnion::make_fact(f->get_var(), FactUnion::BOTTOM); + } } - if (merge_fact(facts, jump_f)) { + if (jump_f && merge_fact(facts, jump_f)) { changed = true; } } @@ -883,7 +856,7 @@ combine_facts(vector& facts1, const FactVec& facts2) for (i=0; iis_related(*new_fact)) { old_fact->join_visits(*new_fact); break; @@ -892,20 +865,6 @@ combine_facts(vector& facts1, const FactVec& facts2) } } -bool -are_facts_in_conflict(const FactVec& facts1, const FactVec& facts2) -{ - for (size_t i=0; iconflict_with(*facts2[j])) { - return true; - } - } - } - return false; -} - bool same_facts(const FactVec& facts1, const FactVec& facts2) { @@ -929,7 +888,7 @@ subset_facts(const FactVec& facts1, const FactVec& facts2) for (i=0; iconflict_with(*f1)) { + if (f2 == 0 || !f2->imply(*f1)) { return false; } } @@ -964,17 +923,21 @@ remove_loop_local_facts(const Statement* s, FactVec& facts) void FactMgr::output_assertions(std::ostream &out, const Statement* stm, int indent, bool post_condition) { - vector& facts = map_facts_out_final[stm]; + vector facts; if (!post_condition) { facts = map_facts_in_final[stm]; - } - if (facts.size() && (stm->eType == eFor || stm->eType == eIfElse)) { + } else { + find_updated_final_facts(stm, facts); + } + if (facts.empty()) return; + + if (stm->eType == eFor || stm->eType == eIfElse) { output_tab(out, indent); std::ostringstream ss; ss << "facts after " << (stm->eType == eFor ? "for loop" : "branching"); output_comment_line(out, ss.str()); } - if (facts.size() && (stm->eType == eAssign || stm->eType == eInvoke || stm->eType == eReturn)) { + if (stm->eType == eAssign || stm->eType == eInvoke || stm->eType == eReturn) { output_tab(out, indent); std::ostringstream ss; ss << "statement id: " << stm->stm_id; @@ -989,17 +952,63 @@ FactMgr::output_assertions(std::ostream &out, const Statement* stm, int indent, if (v->is_global() && !eff.is_read(v) && !eff.is_written(v)) { continue; } - output_tab(out, indent); - // special case for pointto facts, deduce deadness info before print - // todo: use a polymorphism solution if possible - if (f->eCat == ePointTo) { - const FactPointTo* fp = (const FactPointTo*)f; - bool has_invisible = fp->has_invisible(func, stm); - if (has_invisible && fp->get_point_to_vars().size() > 0) { - out << "// "; + output_tab(out, indent); + f->OutputAssertion(out, stm); + } +} + +void +FactMgr::find_updated_facts(const Statement* stm, vector& facts) +{ + const FactVec& facts_in = map_facts_in[stm]; + const FactVec& facts_out = map_facts_out[stm]; + + for (size_t i=0; iequal(*prev_f)) { + facts.push_back(f); + } + } +} + +void +FactMgr::find_updated_final_facts(const Statement* stm, vector& facts) +{ + vector& facts_in = map_facts_in_final[stm]; + vector& facts_out = map_facts_out_final[stm]; + + for (size_t i=0; iget_var() == func->rv) { + facts.push_back(f); + } + else { + const Fact* prev_f = find_related_fact(facts_in, f); + assert(prev_f); + if (!f->equal(*prev_f)) { + facts.push_back(f); + } + } + } +} + +void +FactMgr::find_dangling_global_ptrs(Function* f) +{ + for (size_t i=0; ieCat == ePointTo) { + FactPointTo* fp = (FactPointTo*)(global_facts[i]); + const Variable* v = fp->get_var(); + // const pointers should never be dangling + if (v->is_const() || !v->is_global()) continue; + if (fp->is_dead()) { + f->dead_globals.push_back(v); } } - f->OutputAssertion(out); } } @@ -1057,7 +1066,7 @@ FactMgr::sanity_check_map() const void FactMgr::doFinalization() { - FactPointTo::doFinalization(); + Fact::doFinalization(); meta_facts.clear(); } diff --git a/src/FactMgr.h b/src/FactMgr.h index 1c72cae2c..4f4689149 100644 --- a/src/FactMgr.h +++ b/src/FactMgr.h @@ -110,6 +110,10 @@ class FactMgr void reset_stm_fact_maps(const Statement* stm); void output_assertions(std::ostream &out, const Statement* stm, int indent, bool post_condition); + void find_updated_final_facts(const Statement* stm, vector& facts); + void find_updated_facts(const Statement* stm, vector& facts); + + void find_dangling_global_ptrs(Function* f); /* add paramters facts to env */ void add_param_facts(const vector& param_values, FactVec& facts); @@ -159,9 +163,6 @@ bool merge_jump_facts(FactVec& facts, const FactVec& jump_facts); /* merge one env with a prev env that may miss new variables created recently */ bool merge_prev_facts(FactVec& facts, FactVec& old_facts); -/* check if two facts env are in conflicts */ -bool are_facts_in_conflict(const FactVec& facts1, const FactVec& facts2); - /* check if two facts env are identical */ bool same_facts(const FactVec& facts1, const FactVec& facts2); diff --git a/src/FactPointTo.cpp b/src/FactPointTo.cpp index f02d47af7..817abe394 100644 --- a/src/FactPointTo.cpp +++ b/src/FactPointTo.cpp @@ -57,7 +57,6 @@ const Variable* FactPointTo::garbage_ptr = VariableSelector::make_dummy_static_v const Variable* FactPointTo::tbd_ptr = VariableSelector::make_dummy_static_variable("tbd"); vector FactPointTo::all_ptrs; vector > FactPointTo::all_aliases; -std::vector FactPointTo::facts_; bool FactPointTo::is_null() const @@ -84,18 +83,16 @@ FactPointTo::is_dead() const } bool -FactPointTo::has_invisible(const Function* func, const Statement* stm) const +FactPointTo::has_invisible(const Statement* stm) const { size_t i; - if (!func->is_var_visible(var, stm)) { + if (!var->is_visible(stm->parent)) { return true; } for (i=0; iis_var_visible(v, stm)) { - return true; - } + if (v != null_ptr && v != garbage_ptr && v != tbd_ptr && !v->is_visible(stm->parent)) { + return true; } } return false; @@ -229,7 +226,7 @@ FactPointTo::abstract_fact_for_assign(const std::vector& facts, con case eFuncCall: { const FunctionInvocationUser* fiu = dynamic_cast(fi); // find the fact regarding return variable - FactPointTo* rv_fact = (FactPointTo*)get_return_fact_for_invocation(fiu); + const FactPointTo* rv_fact = (const FactPointTo*)(get_return_fact_for_invocation(fiu, ePointTo)); assert(rv_fact); return FactPointTo::make_facts(lvars, rv_fact->get_point_to_vars()); } @@ -384,28 +381,17 @@ FactPointTo::~FactPointTo(void) { // Nothing else to do. } - -/* - * return 1 if both facts are concerning about the nullness of the same pointer - */ -bool -FactPointTo::is_related(const Fact& f) const -{ - if (eCat == f.eCat) { - const FactPointTo& fact = (const FactPointTo&)f; - return (var == fact.get_var()); - } - return false; -} /* - * return 1 if given facts is for a variable in this point-to set + * return 1 if v (or a field of v) is in the point-to set */ bool -FactPointTo::is_relevant(const Fact& f) const -{ - if (eCat == f.eCat) { - return is_variable_in_set(point_to_vars, f.get_var()); +FactPointTo::point_to(const Variable* v) const +{ + for (size_t i=0; imatch(point_to_vars[i])) { + return true; + } } return false; } @@ -470,10 +456,9 @@ FactPointTo::is_dangling_expr(const Expression* e, const std::vectorget_invoke()->invoke_type == eFuncCall) { const FunctionInvocationUser* fiu = (const FunctionInvocationUser*)(ef->get_invoke()); - const Fact* fact = get_return_fact_for_invocation(fiu); + const FactPointTo* fact = (const FactPointTo*)(get_return_fact_for_invocation(fiu, ePointTo)); if (fact) { - assert(fact->eCat == ePointTo); - return ((const FactPointTo*)fact)->is_dead(); + return fact->is_dead(); } } } @@ -603,17 +588,15 @@ FactPointTo::join_visits(const Fact& f) * return false if point-to already contains point-to-set in f, true otherwise */ bool -FactPointTo::conflict_with(const Fact& f) const +FactPointTo::imply(const Fact& f) const { - // right now, only consider facts of same category. - // compare diff. categories of facts later? if (is_related(f)) { const FactPointTo& fact = (const FactPointTo&)f; if (sub_variable_sets(fact.get_point_to_vars(), point_to_vars)) { - return false; + return true; } } - return true; + return false; } void output_var(const Variable* var, std::ostream &out) @@ -672,22 +655,12 @@ FactPointTo::Output(std::ostream &out) const } } -/* - * output assertion to random program, to check the correctness of compiler - */ -void -FactPointTo::OutputAssertion(std::ostream &out) const +bool +FactPointTo::is_assertable(const Statement* stm) const { - if (point_to_vars.size() > 0) { - // put in comment if the assertion doesn't make sense to compiler - if (is_variable_in_set(point_to_vars, garbage_ptr) || - is_variable_in_set(point_to_vars, tbd_ptr)) { - out << "//"; - } - out << "assert ("; - Output(out); - out << ");" << endl; - } + return !is_variable_in_set(point_to_vars, garbage_ptr) && + !is_variable_in_set(point_to_vars, tbd_ptr) && + !has_invisible(stm); } std::vector @@ -834,16 +807,6 @@ FactPointTo::aggregate_all_pointto_sets(void) assert(all_ptrs.size() == all_aliases.size()); } -void -FactPointTo::doFinalization() -{ - std::vector::iterator i; - for( i = FactPointTo::facts_.begin(); i != FactPointTo::facts_.end(); ++i) { - delete (*i); - } - FactPointTo::facts_.clear(); -} - /////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/src/FactPointTo.h b/src/FactPointTo.h index b5a4c7685..30c256fa3 100644 --- a/src/FactPointTo.h +++ b/src/FactPointTo.h @@ -66,7 +66,7 @@ class FactPointTo : public Fact bool is_null(void) const; bool is_tbd_only(void) const; bool is_dead(void) const; - bool has_invisible(const Function* func, const Statement* stm) const; + bool has_invisible(const Statement* stm) const; int size() const; virtual std::vector abstract_fact_for_assign(const std::vector& facts, const Lhs* lhs, const Expression* rhs); virtual Fact* abstract_fact_for_return(const std::vector& facts, const ExpressionVariable* var, const Function* func); @@ -75,17 +75,21 @@ class FactPointTo : public Fact FactPointTo* mark_func_end(const Statement* stm); const FactPointTo* update_with_modified_index(const Variable* index_var) const; + // lattice functions + virtual bool is_top(void) const { return point_to_vars.empty();} + virtual bool is_bottom(void) const { return false;} // there is no bottom, we just grow the points-to set + virtual void set_top(void) { point_to_vars.clear();} + virtual void set_bottom(void) {}; + virtual int join(const Fact& fact); virtual int join_visits(const Fact& fact); virtual Fact* clone(void) const; - virtual bool conflict_with(const Fact& fact) const; - virtual bool is_related(const Fact& fact) const; - virtual bool is_relevant(const Fact& f) const; + virtual bool imply(const Fact& fact) const; + virtual bool point_to(const Variable* v) const; virtual bool equal(const Fact& fact) const; virtual void Output(std::ostream &out) const; + virtual bool is_assertable(const Statement* s) const; - virtual void OutputAssertion(std::ostream &out) const; - static std::vector merge_pointees_of_pointer(const Variable* ptr, int indirect, const std::vector& facts); static std::vector merge_pointees_of_pointers(const std::vector& ptrs, const std::vector& facts); static void update_facts_with_modified_index(std::vector& facts, const Variable* var); @@ -112,7 +116,6 @@ class FactPointTo : public Fact const Variable* var; vector point_to_vars; - static std::vector facts_; static void update_ptr_aliases(const vector& facts, vector& ptrs, vector >& aliases); diff --git a/src/FactUnion.cpp b/src/FactUnion.cpp new file mode 100644 index 000000000..32d7d6bd0 --- /dev/null +++ b/src/FactUnion.cpp @@ -0,0 +1,292 @@ +// -*- mode: C++ -*- +// +// Copyright (c) 2007, 2008, 2009, 2010, 2011 The University of Utah +// All rights reserved. +// +// This file is part of `csmith', a random generator of C programs. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "FactUnion.h" +#include +#include "Fact.h" +#include "Type.h" +#include "Common.h" +#include "Function.h" +#include "FactMgr.h" +#include "FactPointTo.h" +#include "Lhs.h" +#include "ExpressionVariable.h" +#include "FunctionInvocationUser.h" +#include + +bool FactUnion::type_sensitive = true; +const int FactUnion::TOP = -2; +const int FactUnion::BOTTOM = -1; + +/* + * constructor + */ +FactUnion::FactUnion(const Variable* v) : + Fact(eUnionWrite), + var(v), + last_written_fid(TOP) +{ + // nothing else to do +} + +FactUnion::FactUnion(const Variable* v, int fid) : + Fact(eUnionWrite), + var(v), + last_written_fid(fid) +{ + // nothing else to do +} + +const Type* +FactUnion::get_last_written_type(void) const +{ + assert(var->type && var->type->eType == eUnion); + if (is_top() || is_bottom()) return NULL; + assert (last_written_fid >= 0 && last_written_fid < (int)(var->type->fields.size())); + return var->type->fields[last_written_fid]; +} + +std::vector +FactUnion::rhs_to_lhs_transfer(const std::vector& facts, const vector& lvars, const Expression* rhs) +{ + vector empty; + // assert all possible LHS are unions + for (size_t i=0; itype->eType == eUnion); + } + if (rhs->term_type == eConstant) { + return make_facts(lvars, 0); + } + else if (rhs->term_type == eVariable) { + const ExpressionVariable* expvar = (const ExpressionVariable*)rhs; + int indirect = expvar->get_indirect_level(); + assert (indirect >= 0); + + vector rvars = FactPointTo::merge_pointees_of_pointer(expvar->get_var()->get_collective(), indirect, facts); + const FactUnion* rhs_fact = dynamic_cast(join_var_facts(facts, rvars)); + if (rhs_fact) { + return make_facts(lvars, rhs_fact->get_last_written_fid()); + } + } + else if (rhs->term_type == eFunction) { + const FunctionInvocation* fi = rhs->get_invoke(); + if (fi->invoke_type == eFuncCall) { + const FunctionInvocationUser* fiu = dynamic_cast(fi); + // find the fact regarding return variable + const FactUnion* rv_fact = dynamic_cast(get_return_fact_for_invocation(fiu, eUnionWrite)); + assert(rv_fact); + return make_facts(lvars, rv_fact->get_last_written_fid()); + } + } + return empty; +} + +/* draw facts from an assignment */ +std::vector +FactUnion::abstract_fact_for_assign(const std::vector& facts, const Lhs* lhs, const Expression* rhs) +{ + std::vector ret_facts; + // find all the pointed variables on LHS + std::vector lvars = FactPointTo::merge_pointees_of_pointer(lhs->get_var()->get_collective(), lhs->get_indirect_level(), facts); + if (lhs->get_type().eType == eUnion) { + return rhs_to_lhs_transfer(facts, lvars, rhs); + } + + for (size_t i=0; iis_union_field()) { + fu = make_fact(v->isFieldVarOf_, v->get_field_id()); + } + if (fu) { + ret_facts.push_back(fu); + } + } + return ret_facts; +} + +/* draw facts from return statement */ +Fact* +FactUnion::abstract_fact_for_return(const std::vector& facts, const ExpressionVariable* rv, const Function* func) +{ + if (func->return_type->eType == eUnion) { + int indirect = rv->get_indirect_level(); + assert(indirect >= 0); + vector rvars = FactPointTo::merge_pointees_of_pointer(rv->get_var()->get_collective(), indirect, facts); + const FactUnion* rhs_fact = dynamic_cast(join_var_facts(facts, rvars)); + if (rhs_fact) { + return make_fact(func->rv, rhs_fact->get_last_written_fid()); + } + } + return 0; +} + +Fact* +FactUnion::clone(void) const +{ + FactUnion *fact = new FactUnion(var, last_written_fid); + facts_.push_back(fact); + return fact; +} + +FactUnion * +FactUnion::make_fact(const Variable* v, int fid) +{ + assert(v == NULL || v->type->eType == eUnion); + FactUnion *fact = new FactUnion(v, fid); + facts_.push_back(fact); + return fact; +} + +vector +FactUnion::make_facts(const vector& vars, int fid) +{ + size_t i; + vector facts; + for (i=0; i& facts) +{ + if (v->is_union_field()) { + FactUnion tmp(v->isFieldVarOf_, v->get_field_id()); + const FactUnion* fu = dynamic_cast(find_related_fact(facts, &tmp)); + if (fu && !tmp.imply(*fu)) { + return true; + } + } + return false; +} + +bool +FactUnion::equal(const Fact& f) const +{ + if (is_related(f)) { + const FactUnion& fact = (const FactUnion&)f; + return last_written_fid == fact.get_last_written_fid(); + } + return false; +} + +/* + * return 1 if changed, 0 otherwise. currently facts from diff. categories are not joined + */ +int +FactUnion::join(const Fact& f) +{ + if (is_related(f)) { + if (imply(f)) return 0; + if (f.imply(*this)) { + last_written_fid = ((const FactUnion&)f).get_last_written_fid(); + } else { + set_bottom(); + } + return 1; + } + return 0; +} + +/* + * join facts about a list of vars, return the merged facts + */ +Fact* +FactUnion::join_var_facts(const vector& facts, const vector& vars) const +{ + FactUnion* fu = 0; + for (size_t i=0; i(find_related_fact(facts, &tmp)); + if (exist_fact) { + if (fu == 0) { + fu = dynamic_cast(exist_fact->clone()); + } else { + fu->join(*exist_fact); + } + } + } + return fu; +} + +/* + * return true if this fact is lower than the other fact in lattice + * i.e. merging with the other fact causes no change to this fact + */ +bool +FactUnion::imply(const Fact& f) const +{ + if (is_related(f)) { + if (is_bottom()) return true; // bottom implies every node + const FactUnion& fu = (const FactUnion&)f; + if (fu.is_bottom()) return false; + if (equal(fu)) return true; + + // type sensitive lattice: bottom -> size-determined types -> wider size determined types + // \-> char* -> other pointer types + if (type_sensitive) { + const Type* t = get_last_written_type(); + const Type* other_t = fu.get_last_written_type(); + if (t->eType == ePointer && other_t->eType == ePointer) { + if (t->is_pointer_to_char()) { + return true; + } + return false; + } + if (t->SizeInBytes() == SIZE_UNKNOWN || other_t->SizeInBytes() == SIZE_UNKNOWN) { + return false; + } + if (t->SizeInBytes() <= other_t->SizeInBytes()) { + // only safe is the other field is not bitfield + if (!var->type->is_bitfield(fu.get_last_written_fid())) { + return true; + } + } + } + } + return false; +} + +void +FactUnion::Output(std::ostream &out) const +{ + var->Output(out); + out << " last written field: " << last_written_fid; +} + +/////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// c-basic-offset: 4 +// tab-width: 4 +// End: + +// End of file. diff --git a/src/FactUnion.h b/src/FactUnion.h new file mode 100644 index 000000000..91a83e621 --- /dev/null +++ b/src/FactUnion.h @@ -0,0 +1,108 @@ +// -*- mode: C++ -*- +// +// Copyright (c) 2007, 2008, 2009, 2010, 2011 The University of Utah +// All rights reserved. +// +// This file is part of `csmith', a random generator of C programs. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef FACTUNION_H +#define FACTUNION_H + +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include "Fact.h" +#include "Variable.h" + +class Function; +class Statement; +class Block; +class StatementAssign; +class StatementReturn; + +using namespace std; + +/////////////////////////////////////////////////////////////////////////////// + +class FactUnion : public Fact +{ +public: + static FactUnion *make_fact(const Variable* v, int fid = 0); + static vector make_facts(const vector& vars, int fid); + static void doFinalization(); + static bool is_nonreadable_field(const Variable *v, const std::vector& facts); + + virtual ~FactUnion(void) {}; + + virtual const Variable* get_var(void) const { return var;}; + const Type* get_last_written_type(void) const; + int get_last_written_fid(void) const { return last_written_fid; }; + + // lattice functions + virtual bool is_top(void) const { return last_written_fid == TOP;} + virtual bool is_bottom(void) const { return last_written_fid == BOTTOM;} + virtual void set_top(void) { last_written_fid = TOP;} + virtual void set_bottom(void) { last_written_fid = BOTTOM;} + virtual bool imply(const Fact& fact) const; + virtual bool equal(const Fact& fact) const; + virtual int join(const Fact& fact); + + // transfer functions + vector rhs_to_lhs_transfer(const vector& facts, const vector& lvars, const Expression* rhs); + virtual vector abstract_fact_for_assign(const std::vector& facts, const Lhs* lhs, const Expression* /*rhs*/); + virtual Fact* abstract_fact_for_return(const std::vector& facts, const ExpressionVariable* rv, const Function* func); + virtual Fact* join_var_facts(const vector& facts, const vector& vars) const; + virtual Fact* clone(void) const; + + // output functions + virtual bool is_assertable(const Statement* /*s*/) const { return false;} + virtual void Output(std::ostream &out) const; + virtual void OutputAssertion(std::ostream &/*out*/, const Statement* /*s*/) const {}; + + // flag that indicate the comformance level to C99. 1 means relaxted, 0 means strict + static bool type_sensitive; + // constants to indicate lattice top/bottom + static const int TOP; + static const int BOTTOM; +private: + FactUnion(const Variable* v); + FactUnion(const Variable* v, int fid); + + const Variable* var; + + // last written field id + int last_written_fid; +}; + +/////////////////////////////////////////////////////////////////////////////// + +#endif // FactUnion_H + +// Local Variables: +// c-basic-offset: 4 +// tab-width: 4 +// End: + +// End of file. diff --git a/src/Function.cpp b/src/Function.cpp index c802d9069..fce783f2d 100644 --- a/src/Function.cpp +++ b/src/Function.cpp @@ -329,6 +329,7 @@ Function::Function(const string &name, const Type *return_type) return_type(return_type), body(0), fact_changed(false), + union_field_read(false), visited_cnt(0), build_state(UNBUILT) { @@ -350,7 +351,7 @@ Function::make_random_signature(const CGContext& cg_context, const Type* type, c CVQualifiers ret_qfer = qfer==0 ? CVQualifiers::random_qualifiers(type, Effect::READ, cg_context, true) : qfer->random_qualifiers(true, Effect::READ, cg_context); ERROR_GUARD(NULL); - f->rv = VariableSelector::make_dummy_variable(rvname, &ret_qfer); + f->rv = VariableSelector::make_dummy_variable(rvname, type, &ret_qfer); GenerateParameterList(*f); FMList.push_back(new FactMgr(f)); return f; @@ -383,7 +384,7 @@ Function::make_first(void) string rvname = f->name + "_" + "rv"; CVQualifiers ret_qfer = CVQualifiers::random_qualifiers(ty); ERROR_GUARD(NULL); - f->rv = VariableSelector::make_dummy_variable(rvname, &ret_qfer); + f->rv = VariableSelector::make_dummy_variable(rvname, ty, &ret_qfer); // create a fact manager for this function, with empty global facts FactMgr* fm = new FactMgr(f); @@ -396,18 +397,7 @@ Function::make_first(void) fm->setup_in_out_maps(true); // collect info about global dangling pointers - size_t i; - for (i=0; iglobal_facts.size(); i++) { - const Variable* v = fm->global_facts[i]->get_var(); - // const pointers should never be dangling - if (v->is_const() || !v->is_global()) continue; - if (fm->global_facts[i]->eCat == ePointTo) { - FactPointTo* fp = (FactPointTo*)(fm->global_facts[i]); - if (fp->is_dead()) { - f->dead_globals.push_back(v); - } - } - } + fm->find_dangling_global_ptrs(f); return f; } @@ -500,7 +490,7 @@ Function::Output(std::ostream &out) FactMgr* fm = get_fact_mgr_for_func(this); // if nothing interesting happens, we don't want to see facts for statements - if (!fact_changed && !is_pointer_referenced()) { + if (!fact_changed && !union_field_read && !is_pointer_referenced()) { fm = 0; } body->Output(out, fm); @@ -619,6 +609,7 @@ Function::generate_body_with_known_params(const CGContext &prev_context, Effect& // is just the effect on globals. //effect.add_external_effect(*cg_context.get_effect_accum()); feffect.add_external_effect(fm->map_stm_effect[body]); + union_field_read = fm->map_stm_effect[body].union_field_is_read(); make_return_const(); ERROR_RETURN(); diff --git a/src/Function.h b/src/Function.h index 0ad78eaa3..c7f447512 100644 --- a/src/Function.h +++ b/src/Function.h @@ -113,6 +113,7 @@ class Function std::vector new_globals; // collection of global variables created in this function std::vector dead_globals; // collection of global variables that is dangling at the end of this function bool fact_changed; + bool union_field_read; int visited_cnt; Effect accum_eff_context; diff --git a/src/FunctionInvocation.cpp b/src/FunctionInvocation.cpp index 358d34ddc..cbd6269de 100644 --- a/src/FunctionInvocation.cpp +++ b/src/FunctionInvocation.cpp @@ -478,16 +478,18 @@ FunctionInvocation::visit_facts(vector& inputs, CGContext& cg_conte { bool unordered = false; //has_uncertain_call(); bool ok = false; - //static int g = 0; + static int g = 0; Effect running_eff_context(cg_context.get_effect_context()); if (!unordered) { // unsigned int flags = ptr_cmp ? (cg_context.flags | NO_DANGLING_PTR) : cg_context.flags; for (size_t i=0; ivisit_facts(inputs, param_cg_context)) { return false; } diff --git a/src/FunctionInvocationUser.cpp b/src/FunctionInvocationUser.cpp index 8fffa0fec..59fefd704 100644 --- a/src/FunctionInvocationUser.cpp +++ b/src/FunctionInvocationUser.cpp @@ -70,15 +70,16 @@ static vector invocations; // list of function static vector return_facts; // list of return facts const Fact* -get_return_fact_for_invocation(const FunctionInvocationUser* fiu) +get_return_fact_for_invocation(const FunctionInvocationUser* fiu, enum eFactCategory cat) { - size_t i; assert(invocations.size() == return_facts.size()); - for (i=0; iget_var(); - assert(v == fiu->get_func()->rv); - return return_facts[i]; + for (size_t i=0; ieCat == cat) { + if (invocations[i] == fiu) { + const Variable* v = return_facts[i]->get_var(); + assert(v == fiu->get_func()->rv); + return return_facts[i]; + } } } return 0; @@ -276,7 +277,7 @@ FunctionInvocationUser::build_invocation(Function *target, CGContext &cg_context // in addition, the hack (calling func_1 in a func_1 context) we used would // ruin DFA failed = false; - if (target != GetFirstFunction() && (target->fact_changed || target->is_pointer_referenced())) { + if (target != GetFirstFunction() && (target->fact_changed || target->union_field_read || target->is_pointer_referenced())) { // revisit with a new context Effect effect_accum; // retrive the context effect in prev. visits, and include them for this visit @@ -313,7 +314,8 @@ FunctionInvocationUser::revisit(std::vector& inputs, CGContext& cg_ if (func->visited_cnt++ == 0) { fm->setup_in_out_maps(true); } - if (func->name=="func_8" && (func->visited_cnt==23)) { + // for debugging + if (func->name=="func_8" && func->visited_cnt==2) { //cout << func->visited_cnt << endl; //func->Output(cout); //cout << endl; diff --git a/src/FunctionInvocationUser.h b/src/FunctionInvocationUser.h index cdab93a33..8c682cacf 100644 --- a/src/FunctionInvocationUser.h +++ b/src/FunctionInvocationUser.h @@ -44,13 +44,13 @@ #include #include #include "FunctionInvocation.h" +#include "Type.h" +#include "Fact.h" class CGContext; class Function; class Statement; class Variable; -class Type; -class Fact; class SafeOpFlags; class Variable; @@ -99,7 +99,7 @@ class FunctionInvocationUser: public FunctionInvocation bool build_invocation(Function *target, CGContext &cg_context); }; -const Fact* get_return_fact_for_invocation(const FunctionInvocationUser* fiu); +const Fact* get_return_fact_for_invocation(const FunctionInvocationUser* fiu, enum eFactCategory cat); void calls_to_funcs(const vector& calls, vector& funcs); void calls_to_funcs_recursive(const vector& calls, vector& funcs); diff --git a/src/Statement.cpp b/src/Statement.cpp index eca492fe6..d60cd7db3 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -347,10 +347,10 @@ Statement::is_ptr_used(void) const /* * */ -Statement::Statement(eStatementType st) +Statement::Statement(eStatementType st, Block* b) : eType(st), - func(0), - parent(0) + func(b ? b->func : 0), + parent(b) { stm_id = Statement::sid; Statement::sid++; @@ -377,40 +377,6 @@ Statement::in_block(const Block* b) const } return false; } -// -//int -//Statement::get_blocks(std::vector& blks) const -//{ -// blks.clear(); -// switch (eType) -// { -// case eBlock: -// blks.push_back((const Block*)this); -// break; -// case eIfElse:{ -// const StatementIf* si = (const StatementIf*)this; -// blks.push_back(si->get_true_branch()); -// blks.push_back(si->get_false_branch()); -// break; -// } -// case eFor: { -// const StatementFor* sf = (const StatementFor*)this; -// blks.push_back(sf->get_body()); -// break; -// } -// case eArrayOp: { -// const StatementArrayOp* sa = (const StatementArrayOp*)this; -// if (sa->body) { -// blks.push_back(sa->body); -// } -// break; -// } -// default: -// break; -// } -// return blks.size(); -//} - /* * return true if this statement dominates s @@ -637,7 +603,6 @@ Statement::validate_and_update_facts(vector& inputs, CGContext& cg_ if (!stm_visit_facts(inputs, cg_context)) { return false; } - fm->remove_rv_facts(inputs); fm->set_fact_in(this, inputs_copy); fm->set_fact_out(this, inputs); return true; @@ -653,11 +618,13 @@ Statement::stm_visit_facts(vector& inputs, CGContext& cg_context) c //int h = g++; bool ok = visit_facts(inputs, cg_context); + if (!ok && !is_compound(eType)) { failed_stm = this; } //if (!FactPointTo::is_valid_ptr("g_75", inputs)) // Output(cout, fm); + fm->remove_rv_facts(inputs); fm->map_accum_effect[this] = *(cg_context.get_effect_accum()); fm->map_visited[this] = true; return ok; @@ -844,14 +811,9 @@ Statement::contains_unfixed_goto(void) const for (j=0; jmap_facts_in[edge->dest].size(); j++) { const Fact* f = fm->map_facts_in[edge->dest][j]; // ignore return variable facts - if (f->get_var()->type != 0) { + if (!f->get_var()->is_rv()) { const Fact* jump_src_f = find_related_fact(fm->map_facts_out[edge->src], f); - // JYTODO: cover all fact categories - FactPointTo tmp(f->get_var()); - if (jump_src_f == 0) { - jump_src_f = &tmp; - } - if (f->conflict_with(*jump_src_f)) { + if (jump_src_f && !f->imply(*jump_src_f)) { return true; } } @@ -923,13 +885,14 @@ Statement::post_creation_analysis(vector& pre_facts, const Effect& if (has_uncertain_call_recursive()) { FactVec outputs = pre_facts; cg_context.reset_effect_accum(pre_effect); - //if (stm_id==848) { - // if (this->eType == eAssign) { - // ((const StatementAssign*)this)->get_rhs()->indented_output(cout, 0); - // } - // Output(cout, fm); - //} + //if (stm_id == 573) + // BREAK_NOP; if (!validate_and_update_facts(outputs, cg_context)) { + /*if (this->eType == eAssign) { + ((const StatementAssign*)this)->get_rhs()->indented_output(cout, 0); + } + cout << endl; + Output(cout, fm);*/ assert(0); } fm->global_facts = outputs; diff --git a/src/Statement.h b/src/Statement.h index 8ae21b998..4229f2272 100644 --- a/src/Statement.h +++ b/src/Statement.h @@ -182,7 +182,7 @@ class Statement static ProbabilityTable *stmtTable_; protected: - Statement(eStatementType st); + Statement(eStatementType st, Block* parent); private: static int sid; diff --git a/src/StatementArrayOp.cpp b/src/StatementArrayOp.cpp index 9e9488f8b..6d1fcdd3a 100644 --- a/src/StatementArrayOp.cpp +++ b/src/StatementArrayOp.cpp @@ -122,7 +122,7 @@ StatementArrayOp::make_random_array_init(CGContext &cg_context) if (CGOptions::strict_const_arrays()) assert(av->type->eType != ePointer); assert(init->visit_facts(fm->global_facts, cg_context)); - StatementArrayOp* sa = new StatementArrayOp(av, cvs, inits, incrs, init); + StatementArrayOp* sa = new StatementArrayOp(cg_context.get_current_block(), av, cvs, inits, incrs, init); Lhs lhs(*av); if (update_fact_for_assign(&lhs, init, fm->global_facts)) { cg_context.get_current_func()->fact_changed = true; @@ -134,12 +134,12 @@ StatementArrayOp::make_random_array_init(CGContext &cg_context) /* * */ -StatementArrayOp::StatementArrayOp(const ArrayVariable* av, +StatementArrayOp::StatementArrayOp(Block* b, const ArrayVariable* av, const std::vector& cvs, const std::vector& inits, const std::vector& incrs, const Block *body) - : Statement(eArrayOp), + : Statement(eArrayOp, b), array_var(av), ctrl_vars(cvs), inits(inits), @@ -153,12 +153,12 @@ StatementArrayOp::StatementArrayOp(const ArrayVariable* av, /* * */ -StatementArrayOp::StatementArrayOp(const ArrayVariable* av, +StatementArrayOp::StatementArrayOp(Block* b, const ArrayVariable* av, const std::vector& cvs, const std::vector& inits, const std::vector& incrs, const Expression *e) - : Statement(eArrayOp), + : Statement(eArrayOp, b), array_var(av), ctrl_vars(cvs), inits(inits), diff --git a/src/StatementArrayOp.h b/src/StatementArrayOp.h index 63866510f..aaec07628 100644 --- a/src/StatementArrayOp.h +++ b/src/StatementArrayOp.h @@ -52,12 +52,12 @@ class StatementArrayOp : public Statement // Factory method. static Statement *make_random(CGContext &cg_context); static StatementArrayOp *make_random_array_init(CGContext &cg_context); - StatementArrayOp(const ArrayVariable* av, + StatementArrayOp(Block* b, const ArrayVariable* av, const std::vector& cvs, const std::vector& inits, const std::vector& incrs, const Block *body); - StatementArrayOp(const ArrayVariable* av, + StatementArrayOp(Block* b, const ArrayVariable* av, const std::vector& cvs, const std::vector& inits, const std::vector& incrs, diff --git a/src/StatementAssign.cpp b/src/StatementAssign.cpp index 3a80c2186..06e75a6e2 100644 --- a/src/StatementAssign.cpp +++ b/src/StatementAssign.cpp @@ -184,7 +184,6 @@ StatementAssign::make_random(CGContext &cg_context) cg_context.add_effect(lhs_accum); cg_context.get_effect_stm() = lhs_cg_context.get_effect_stm(); - //} while (fm->validate_assign(lhs, e)==false); // book keeping incr_counter(Bookkeeper::expr_depth_cnts, cg_context.expr_depth); @@ -268,7 +267,7 @@ StatementAssign::make_possible_compound_assign(CGContext &cg_context, ERROR_GUARD(NULL); } } - StatementAssign *sa = new StatementAssign(l, op, e, rhs, fs, tmp1, tmp2); + StatementAssign *sa = new StatementAssign(cg_context.get_current_block(), l, op, e, rhs, fs, tmp1, tmp2); return sa; } @@ -299,11 +298,7 @@ StatementAssign::compound_to_binary_ops(eAssignOps op) bool StatementAssign::visit_facts(vector& inputs, CGContext& cg_context) const -{ - static int g = 0; - int h = g++; - if (h==57) - BREAK_NOP; +{ vector inputs_copy = inputs; // LHS and RHS can be evaludated in arbitrary order, try RHS first Effect running_eff_context(cg_context.get_effect_context()); @@ -347,11 +342,11 @@ StatementAssign::has_uncertain_call_recursive(void) const /* * */ -StatementAssign::StatementAssign(const Lhs &l, +StatementAssign::StatementAssign(Block* b, const Lhs &l, const Expression &e, eAssignOps op, const SafeOpFlags *flags) - : Statement(eAssign), + : Statement(eAssign, b), op(op), lhs(l), expr(e), @@ -364,14 +359,14 @@ StatementAssign::StatementAssign(const Lhs &l, /* * */ -StatementAssign::StatementAssign(const Lhs &l, +StatementAssign::StatementAssign(Block* b, const Lhs &l, eAssignOps op, const Expression &e, const Expression *er, const SafeOpFlags *flags, std::string &tmp_name1, std::string &tmp_name2) - : Statement(eAssign), + : Statement(eAssign, b), op(op), lhs(l), expr(e), diff --git a/src/StatementAssign.h b/src/StatementAssign.h index 66d863f29..d0663ff00 100644 --- a/src/StatementAssign.h +++ b/src/StatementAssign.h @@ -87,9 +87,9 @@ class StatementAssign : public Statement eAssignOps op, const Expression &e); - StatementAssign(const Lhs &l, const Expression &e, eAssignOps op = eSimpleAssign, const SafeOpFlags *flags = NULL); + StatementAssign(Block* b, const Lhs &l, const Expression &e, eAssignOps op = eSimpleAssign, const SafeOpFlags *flags = NULL); - StatementAssign(const Lhs &l, eAssignOps op, const Expression &e, + StatementAssign(Block* b, const Lhs &l, eAssignOps op, const Expression &e, const Expression *er, const SafeOpFlags *flags, std::string &tmp_name1, std::string &tmp_name2); diff --git a/src/StatementBreak.cpp b/src/StatementBreak.cpp index 57316168f..ce22c686c 100644 --- a/src/StatementBreak.cpp +++ b/src/StatementBreak.cpp @@ -72,7 +72,7 @@ StatementBreak::make_random(CGContext &cg_context) cg_context.get_effect_stm().clear(); Expression *expr = Expression::make_random(cg_context, get_int_type(), true, true, eVariable); ERROR_GUARD(NULL); - StatementBreak* sc = new StatementBreak(*expr, *b); + StatementBreak* sc = new StatementBreak(cg_context.get_current_block(), *expr, *b); b->break_stms.push_back(sc); return sc; } @@ -80,8 +80,8 @@ StatementBreak::make_random(CGContext &cg_context) /* * */ -StatementBreak::StatementBreak(const Expression &test, const Block &b) - : Statement(eBreak), +StatementBreak::StatementBreak(Block* parent, const Expression &test, const Block &b) + : Statement(eBreak, parent), test(test), loop_blk(b) { @@ -92,7 +92,7 @@ StatementBreak::StatementBreak(const Expression &test, const Block &b) * */ StatementBreak::StatementBreak(const StatementBreak &sc) - : Statement(sc.get_type()), +: Statement(sc.get_type(), sc.parent), test(sc.test), loop_blk(sc.loop_blk) { diff --git a/src/StatementBreak.h b/src/StatementBreak.h index 6f8084087..dacdd154b 100644 --- a/src/StatementBreak.h +++ b/src/StatementBreak.h @@ -46,7 +46,7 @@ class StatementBreak : public Statement // Factory method. static StatementBreak *make_random(CGContext &cg_context); - StatementBreak(const Expression &test, const Block& b); + StatementBreak(Block* parent, const Expression &test, const Block& b); StatementBreak(const StatementBreak &sc); virtual ~StatementBreak(void); // diff --git a/src/StatementContinue.cpp b/src/StatementContinue.cpp index 208c213fa..e106f3482 100644 --- a/src/StatementContinue.cpp +++ b/src/StatementContinue.cpp @@ -72,7 +72,7 @@ StatementContinue::make_random(CGContext &cg_context) cg_context.get_effect_stm().clear(); Expression *expr = Expression::make_random(cg_context, get_int_type(), true, true, eVariable); ERROR_GUARD(NULL); - StatementContinue* sc = new StatementContinue(*expr, *b); + StatementContinue* sc = new StatementContinue(cg_context.get_current_block(), *expr, *b); fm->create_cfg_edge(sc, b, false, true); return sc; } @@ -80,8 +80,8 @@ StatementContinue::make_random(CGContext &cg_context) /* * */ -StatementContinue::StatementContinue(const Expression &test, const Block &b) - : Statement(eContinue), +StatementContinue::StatementContinue(Block* parent, const Expression &test, const Block &b) + : Statement(eContinue, parent), test(test), loop_blk(b) { @@ -92,7 +92,7 @@ StatementContinue::StatementContinue(const Expression &test, const Block &b) * */ StatementContinue::StatementContinue(const StatementContinue &sc) - : Statement(sc.get_type()), +: Statement(sc.get_type(), sc.parent), test(sc.test), loop_blk(sc.loop_blk) { diff --git a/src/StatementContinue.h b/src/StatementContinue.h index 051b768f4..ff8638c2e 100644 --- a/src/StatementContinue.h +++ b/src/StatementContinue.h @@ -46,7 +46,7 @@ class StatementContinue : public Statement // Factory method. static StatementContinue *make_random(CGContext &cg_context); - StatementContinue(const Expression &test, const Block& b); + StatementContinue(Block* parent, const Expression &test, const Block& b); StatementContinue(const StatementContinue &sc); virtual ~StatementContinue(void); // diff --git a/src/StatementExpr.cpp b/src/StatementExpr.cpp index ea2f3d98c..916f92042 100644 --- a/src/StatementExpr.cpp +++ b/src/StatementExpr.cpp @@ -64,14 +64,14 @@ StatementExpr::make_random(CGContext &cg_context) delete invoke; return 0; } - return new StatementExpr(*invoke); + return new StatementExpr(cg_context.get_current_block(), *invoke); } /* * */ -StatementExpr::StatementExpr(const FunctionInvocation &e) - : Statement(eInvoke), +StatementExpr::StatementExpr(Block* b, const FunctionInvocation &e) + : Statement(eInvoke, b), expr(e) { // Nothing else to do. @@ -81,7 +81,7 @@ StatementExpr::StatementExpr(const FunctionInvocation &e) * */ StatementExpr::StatementExpr(const StatementExpr &se) - : Statement(se.get_type()), +: Statement(se.get_type(), se.parent), expr(*se.get_invoke()) { // Nothing else to do. diff --git a/src/StatementExpr.h b/src/StatementExpr.h index 42b8921d1..1371cbc8f 100644 --- a/src/StatementExpr.h +++ b/src/StatementExpr.h @@ -52,7 +52,7 @@ class StatementExpr : public Statement // Factory method. static StatementExpr *make_random(CGContext &cg_context); - StatementExpr(const FunctionInvocation &e); + StatementExpr(Block* b, const FunctionInvocation &e); StatementExpr(const StatementExpr &se); virtual ~StatementExpr(void); diff --git a/src/StatementFor.cpp b/src/StatementFor.cpp index 62244711f..6b0d8f398 100644 --- a/src/StatementFor.cpp +++ b/src/StatementFor.cpp @@ -197,7 +197,7 @@ StatementFor::make_iteration(CGContext& cg_context, StatementAssign*& init, Expr SafeOpFlags *flags1 = SafeOpFlags::make_random(sOpAssign); ERROR_GUARD_AND_DEL2(NULL, c_init, lhs); - init = new StatementAssign(*lhs, *c_init, eSimpleAssign, flags1); + init = new StatementAssign(cg_context.get_current_block(), *lhs, *c_init, eSimpleAssign, flags1); ERROR_GUARD_AND_DEL3(NULL, c_init, lhs, flags1); assert(init->visit_facts(fm->global_facts, cg_context)); @@ -226,7 +226,7 @@ StatementFor::make_iteration(CGContext& cg_context, StatementAssign*& init, Expr ERROR_GUARD_AND_DEL3(NULL, init, test, lhs1); if (bound != INVALID_BOUND) { - incr = new StatementAssign(*lhs1, *c_incr, incr_op); + incr = new StatementAssign(cg_context.get_current_block(), *lhs1, *c_incr, incr_op); } else { incr = StatementAssign::make_possible_compound_assign(cg_context, *lhs1, incr_op, *c_incr); } @@ -241,8 +241,6 @@ StatementFor::make_random(CGContext &cg_context) { FactMgr* fm = get_fact_mgr(&cg_context); assert(fm); - // save a copy of facts env and context - vector pre_facts = fm->global_facts; cg_context.get_effect_stm().clear(); StatementAssign* init = NULL; @@ -250,14 +248,16 @@ StatementFor::make_random(CGContext &cg_context) Expression* test = NULL; unsigned int bound = 0; const Variable* iv = make_iteration(cg_context, init, test, incr, bound); - // record the effect before loop body + // record the effect and facts before loop body Effect pre_effects = cg_context.get_effect_stm(); + vector pre_facts = fm->global_facts; + // create CGContext for body CGContext body_cg_context(cg_context, cg_context.rw_directive, iv, bound); Block *body = Block::make_random(body_cg_context, true); ERROR_GUARD_AND_DEL3(NULL, init, test, incr); - StatementFor* sf = new StatementFor(*init, *test, *incr, *body); + StatementFor* sf = new StatementFor(cg_context.get_current_block(), *init, *test, *incr, *body); sf->post_loop_analysis(cg_context, pre_facts, pre_effects); return sf; } @@ -323,11 +323,11 @@ StatementFor::post_loop_analysis(CGContext& cg_context, vector& pre /* * */ -StatementFor::StatementFor(const StatementAssign &init, +StatementFor::StatementFor(Block* b, const StatementAssign &init, const Expression &test, const StatementAssign &incr, const Block &body) - : Statement(eFor), + : Statement(eFor, b), init(init), test(test), incr(incr), diff --git a/src/StatementFor.h b/src/StatementFor.h index 1041a7123..fb5c0924a 100644 --- a/src/StatementFor.h +++ b/src/StatementFor.h @@ -55,7 +55,8 @@ class StatementFor : public Statement static const Variable* make_iteration(CGContext& cg_context, StatementAssign*& begin, Expression*& exit_cond, StatementAssign*& step, unsigned int& bound); - StatementFor(const StatementAssign &init, + StatementFor(Block* b, + const StatementAssign &init, const Expression &test, const StatementAssign &incr, const Block &body); diff --git a/src/StatementGoto.cpp b/src/StatementGoto.cpp index 77a198c8b..133278fe3 100644 --- a/src/StatementGoto.cpp +++ b/src/StatementGoto.cpp @@ -112,11 +112,15 @@ StatementGoto::make_random(CGContext &cg_context) cg_context.get_effect_stm().clear(); //Expression* test = Expression::make_random(cg_context, get_int_type(), true, true, eVariable); // use a variable that is already read in the context to avoid introducing conflict by the condition - const vector& write_vars = back_edge ? - cg_context.get_effect_accum()->get_read_vars() : - fm->map_accum_effect[other_stm].get_read_vars(); - const Block* b = back_edge ? curr_blk : ok_blk; - const Variable* cond_var = VariableSelector::choose_visible_written_var(b, write_vars, get_int_type()); + const Variable* cond_var = NULL; + if (back_edge) { + cond_var = VariableSelector::choose_visible_read_var(curr_blk, + cg_context.get_effect_accum()->get_read_vars(), get_int_type(), fm->global_facts); + } else { + // travel in time, find a suitable variable read at generation time of the other statement + cond_var = VariableSelector::choose_visible_read_var(ok_blk, + fm->map_accum_effect[other_stm].get_read_vars(), get_int_type(), fm->map_facts_out[other_stm]); + } if (cond_var == 0) { return NULL; } @@ -147,8 +151,7 @@ StatementGoto::make_random(CGContext &cg_context) bool ok = true; bool found_new_facts = false; // JYTODO: don't assume facts_in == facts_out for control statements - FactVec& goto_in = other_stm->is_ctrl_stmt() ? fm->map_facts_in[other_stm] : fm->map_facts_out[other_stm]; - fm->remove_rv_facts(goto_in); + FactVec& goto_in = other_stm->is_ctrl_stmt() ? fm->map_facts_in[other_stm] : fm->map_facts_out[other_stm]; update_facts_for_dest(goto_in, goto_out, stm); stm_in = fm->map_facts_in[stm]; Effect pre_effect = cg_context.get_accum_effect(); @@ -206,14 +209,12 @@ StatementGoto::make_random(CGContext &cg_context) /* * */ -StatementGoto::StatementGoto(Block* blk, const Expression &test, const Statement* dest, const std::vector& vars) - : Statement(eGoto), +StatementGoto::StatementGoto(Block* b, const Expression &test, const Statement* dest, const std::vector& vars) + : Statement(eGoto, b), test(test), dest(dest), init_skipped_vars(vars) { - parent = blk; - func = dest->func; if (stm_labels.find(dest) != stm_labels.end()){ label = stm_labels[dest]; } @@ -227,7 +228,7 @@ StatementGoto::StatementGoto(Block* blk, const Expression &test, const Statement * */ StatementGoto::StatementGoto(const StatementGoto &sg) - : Statement(sg.get_type()), +: Statement(sg.get_type(), sg.parent), test(sg.test), dest(sg.dest), label(sg.label), diff --git a/src/StatementGoto.h b/src/StatementGoto.h index f6c6d02c2..3927c4af1 100644 --- a/src/StatementGoto.h +++ b/src/StatementGoto.h @@ -51,7 +51,7 @@ class StatementGoto : public Statement // Factory method. static StatementGoto *make_random(CGContext &cg_context); - StatementGoto(Block* blk, const Expression &test, const Statement* dest, const std::vector& vars); + StatementGoto(Block* b, const Expression &test, const Statement* dest, const std::vector& vars); StatementGoto(const StatementGoto &sg); virtual ~StatementGoto(void); // diff --git a/src/StatementIf.cpp b/src/StatementIf.cpp index 90340220e..1b9ce5294 100644 --- a/src/StatementIf.cpp +++ b/src/StatementIf.cpp @@ -97,7 +97,7 @@ StatementIf::make_random(CGContext &cg_context) Block *if_false = Block::make_random(cg_context); ERROR_GUARD_AND_DEL2(NULL, expr, if_true); - StatementIf* si = new StatementIf(*expr, *if_true, *if_false); + StatementIf* si = new StatementIf(cg_context.get_current_block(), *expr, *if_true, *if_false); // compute accumulated effect for this statement si->set_accumulated_effect_after_block(eff, if_true, cg_context); si->set_accumulated_effect_after_block(eff, if_false, cg_context); @@ -107,9 +107,9 @@ StatementIf::make_random(CGContext &cg_context) /* * */ -StatementIf::StatementIf(const Expression &test, +StatementIf::StatementIf(Block* b, const Expression &test, const Block &if_true, const Block &if_false) - : Statement(eIfElse), + : Statement(eIfElse, b), test(test), if_true(if_true), if_false(if_false) @@ -121,7 +121,7 @@ StatementIf::StatementIf(const Expression &test, * */ StatementIf::StatementIf(const StatementIf &si) - : Statement(si.get_type()), + : Statement(si.get_type(), si.parent), test(si.test), if_true(si.if_true), if_false(si.if_false) diff --git a/src/StatementIf.h b/src/StatementIf.h index b4782d780..ba142fb5d 100644 --- a/src/StatementIf.h +++ b/src/StatementIf.h @@ -50,7 +50,7 @@ class StatementIf : public Statement // Factory method. static StatementIf *make_random(CGContext &cg_context); - StatementIf(const Expression &test, + StatementIf(Block* b, const Expression &test, const Block &if_true, const Block &if_false); StatementIf(const StatementIf &si); virtual ~StatementIf(void); diff --git a/src/StatementReturn.cpp b/src/StatementReturn.cpp index 1ec7e53e9..e49320fc5 100644 --- a/src/StatementReturn.cpp +++ b/src/StatementReturn.cpp @@ -64,7 +64,7 @@ StatementReturn::make_random(CGContext &cg_context) ERROR_GUARD(NULL); incr_counter(Bookkeeper::expr_depth_cnts, cg_context.expr_depth); - StatementReturn* sr = new StatementReturn(*ev); + StatementReturn* sr = new StatementReturn(cg_context.get_current_block(), *ev); return sr; } @@ -99,8 +99,8 @@ StatementReturn::visit_facts(vector& inputs, CGContext& cg_context) /* * */ -StatementReturn::StatementReturn(const ExpressionVariable &v) - : Statement(eReturn), +StatementReturn::StatementReturn(Block* b, const ExpressionVariable &v) + : Statement(eReturn, b), var(v) { // Nothing else to do. @@ -110,7 +110,7 @@ StatementReturn::StatementReturn(const ExpressionVariable &v) * */ StatementReturn::StatementReturn(const StatementReturn &sr) - : Statement(sr.get_type()), + : Statement(sr.get_type(), sr.parent), var(sr.var) { // Nothing else to do. diff --git a/src/StatementReturn.h b/src/StatementReturn.h index e773319f1..1c74ea7c8 100644 --- a/src/StatementReturn.h +++ b/src/StatementReturn.h @@ -51,7 +51,7 @@ class StatementReturn : public Statement // Factory method. static StatementReturn *make_random(CGContext &cg_context); - StatementReturn(const ExpressionVariable &v); + StatementReturn(Block* b, const ExpressionVariable &v); StatementReturn(const StatementReturn &sr); virtual ~StatementReturn(void); diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 21fa90c64..0a1f1e817 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -261,6 +261,15 @@ StringUtils::breakup_assigns(const string& assigns, vector& vars, vector } } +bool +StringUtils::end_with(string s, string tail) +{ + if (tail.length() < s.length()) { + s = s.substr(s.length() - tail.length()); + } + return s == tail; +} + ////////////////////////////////////////////////////////////////////////////// StringUtils::StringUtils() { diff --git a/src/StringUtils.h b/src/StringUtils.h index 60680a82b..df543b37d 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -41,6 +41,8 @@ class StringUtils { static bool is_space(const char c); + static bool end_with(string s, string tail); + static void ignore_spaces(const std::string &str, size_t &pos); static std::string get_substring(const std::string &s, const char open_delim, const char close_delim); diff --git a/src/Type.cpp b/src/Type.cpp index 8bf3aeae2..c80e3b140 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -39,6 +39,7 @@ #include "Type.h" #include #include +#include #include "Common.h" #include "CGOptions.h" #include "random.h" @@ -536,13 +537,13 @@ Type::random_type_from_type(const Type* type, bool no_volatile, bool strict_simp // --------------------------------------------------------------------- static bool -AllTypesProbability(void) +MoreTypesProbability(void) { // Always have at least 10 types in the program. if (AllTypes.size() < 10) return true; - // 50% probability for each additional type. - return rnd_flipcoin(50); + // 60% probability for each additional type. + return rnd_flipcoin(60); } // --------------------------------------------------------------------- @@ -634,16 +635,36 @@ Type::make_one_union_field(vector &fields, vector &qf } else { vector ok_types = AllTypes; - ok_types.insert(ok_types.end(), derived_types.begin(), derived_types.end()); + // find locations of struct types + int start_index = -1; + int end_index = -1; + for (size_t i=0; ieType == eStruct) { + if (start_index == -1) start_index = i; + end_index = i; + } + } const Type* type = NULL; do { - unsigned int i = pure_rnd_upto(ok_types.size()); - const Type* t = ok_types[i]; - // no union in union? - if (t->eType == eUnion || t->eType == eSimple && SIMPLE_TYPES_PROB_FILTER->filter(t->simple_type)) { - continue; + // 10% chance to be struct field + if (start_index != -1 && pure_rnd_flipcoin(10)) { + type = ok_types[start_index + pure_rnd_upto(end_index - start_index + 1)]; + assert(type->eType == eStruct); + } + // 10% chance to be char* + else if (pure_rnd_flipcoin(10)) { + type = find_pointer_type(&get_simple_type(eChar), true); + } + else { + unsigned int i = pure_rnd_upto(ok_types.size()); + const Type* t = ok_types[i]; + // no union in union? + if (t->eType == eUnion || + (t->eType == eSimple && SIMPLE_TYPES_PROB_FILTER->filter(t->simple_type))) { + continue; + } + type = t; } - type = t; } while (type == NULL); fields.push_back(type); @@ -1058,17 +1079,13 @@ GenerateAllTypes(void) Type::GenerateSimpleTypes(); if (CGOptions::use_struct()) { - while (AllTypesProbability()) { + while (MoreTypesProbability()) { Type *ty = Type::make_random_struct_type(); AllTypes.push_back(ty); } } if (CGOptions::use_union()) { - // create some pointer types to be the fields of unions - while (derived_types.size() < 10 && pure_rnd_flipcoin(50)) { - Type::find_pointer_type(Type::choose_random(), true); - } - while (AllTypesProbability()) { + while (MoreTypesProbability()) { Type *ty = Type::make_random_union_type(); AllTypes.push_back(ty); } @@ -1374,8 +1391,14 @@ Type::SizeInBytes(void) const break; case eUnion: { unsigned int max_size = 0; - for (i=0; iSizeInBytes(); + for (i=0; i= 0 && i < bitfields_length_.size()); + sz = ceil(bitfields_length_[i] / 8.0) * 8; + } else { + sz = fields[i]->SizeInBytes(); + } if (sz == SIZE_UNKNOWN) return sz; if (sz > max_size) { max_size = sz; @@ -1385,9 +1408,12 @@ Type::SizeInBytes(void) const } case eStruct: { if (!this->packed_) return SIZE_UNKNOWN; + // give up if there are bitfields, too much compiler-dependence and machine-dependence + if (this->has_bitfields()) return SIZE_UNKNOWN; unsigned int total_size = 0; for (i=0; iSizeInBytes(); + unsigned int sz = fields[i]->SizeInBytes(); + total_size += sz; } return total_size; } diff --git a/src/Type.h b/src/Type.h index 03ca8c3d1..0661a9f0f 100644 --- a/src/Type.h +++ b/src/Type.h @@ -216,6 +216,7 @@ class Type void get_int_subfield_names(string prefix, vector& names) const; bool is_signed(void) const; const Type* to_unsigned(void) const; + bool is_pointer_to_char(void) const { return ptr_type && ptr_type->eType == eSimple && (ptr_type->simple_type==eChar || ptr_type->simple_type==eUChar);} bool is_promotable(const Type* t) const; bool is_convertable(const Type* t) const; bool is_derivable(const Type* t) const; diff --git a/src/Variable.cpp b/src/Variable.cpp index 431afc68a..f2b3fa1f5 100644 --- a/src/Variable.cpp +++ b/src/Variable.cpp @@ -204,11 +204,20 @@ void remove_field_vars(vector& set) /* * examples: array[0] "loose matches" array[1]; array[3] "loose matches" array[x].f1... + * union.f1 "loose matches" union.f2 */ bool Variable::loose_match(const Variable* v) const { - return get_collective()->match(v->get_collective()); + const Variable* me = get_collective(); + const Variable* you = v->get_collective(); + if (me->match(you)) { + return true; + } + if (me->isFieldVarOf_== you->isFieldVarOf_ && me->is_union_field()) { + return true; + } + return false; } /* @@ -275,6 +284,19 @@ bool Variable::has_field_var(const Variable* v) const return false; } +int +Variable::get_field_id(void) const +{ + if (isFieldVarOf_) { + for (size_t i=0; ifield_vars.size(); i++) { + if (isFieldVarOf_->field_vars[i] == this) { + return i; + } + } + } + return -1; +} + /////////////////////////////////////////////////////////////////////////////// /* expand field variables of struct, assigned names, f0, f1, etc, to them ************************************************************************/ diff --git a/src/Variable.h b/src/Variable.h index 390373269..08b7e4ab3 100644 --- a/src/Variable.h +++ b/src/Variable.h @@ -50,6 +50,7 @@ using namespace std; #include "Effect.h" #include "Type.h" #include "CVQualifiers.h" +#include "StringUtils.h" class CGContext; class Expression; @@ -87,6 +88,7 @@ class Variable bool is_volatile_after_deref(int deref_level) const; bool has_field_var(const Variable* v) const; bool is_field_var(void) const { return isFieldVarOf_ != 0; }; + int get_field_id(void) const; bool is_union_field(void) const { return isFieldVarOf_ != 0 && isFieldVarOf_->type->eType == eUnion; }; bool is_array_field(void) const; bool is_virtual(void) const; @@ -94,6 +96,7 @@ class Variable bool match(const Variable* v) const; bool loose_match(const Variable* v) const; bool is_pointer(void) const { return type && type->eType == ePointer;} + bool is_rv(void) const { return StringUtils::end_with(name, "_rv"); } int get_seq_num(void) const; virtual std::string get_actual_name() const; diff --git a/src/VariableSelector.cpp b/src/VariableSelector.cpp index 91e32c52f..af575aef2 100644 --- a/src/VariableSelector.cpp +++ b/src/VariableSelector.cpp @@ -46,6 +46,7 @@ #include "Fact.h" #include "FactMgr.h" #include "FactPointTo.h" +#include "FactUnion.h" #include "random.h" #include "util.h" #include "Lhs.h" @@ -356,19 +357,20 @@ VariableSelector::choose_ok_var(const vector &vars) } const Variable * -VariableSelector::choose_visible_written_var(const Block* b, vector written_vars, const Type* type) +VariableSelector::choose_visible_read_var(const Block* b, vector read_vars, const Type* type, const FactVec& facts) { size_t i; vector ok_vars; - // include the fields of structs - expand_struct_union_vars(written_vars, type); + // include the fields of struct/unions + expand_struct_union_vars(read_vars, type); - for (i=0; imatch(v->type, eConvert) && (b->is_var_on_stack(v) || v->is_global()) && !v->is_virtual() && - !v->is_volatile()) { + !v->is_volatile() && + !FactUnion::is_nonreadable_field(v, facts)) { ok_vars.push_back(v); } } @@ -725,40 +727,6 @@ VariableSelector::find_all_visible_vars(const Block* b) return vars; } -/* remove not-qualified variables from candidate list, not used for now */ -void -VariableSelector::remove_non_qualified_vars(vector& vars, Effect::Access access, const CGContext &cg_context) -{ - size_t i; - size_t len = vars.size(); - const Effect& eff = cg_context.get_effect_context(); - for (i=0; iis_const()) { - ok = false; - } - if (eff.is_read(v) || eff.is_written(v)) { - ok = false; - } - } - else if (access==Effect::READ) { - if (eff.is_written(v)) { - ok = false; - } - } - if (!eff.is_side_effect_free() && v->is_volatile()) { - ok = false; - } - if (!ok) { - vars.erase(vars.begin() + i); - i--; - len--; - } - } -} - /* * enlarge the block to contains both src and dest of jump edges, if there are * some destinations in this block. This is used to create a local variable @@ -1465,9 +1433,9 @@ VariableSelector::create_mutated_array_var(const ArrayVariable* av, const vector } Variable * -VariableSelector::make_dummy_variable(const string &name, const CVQualifiers* qfer) +VariableSelector::make_dummy_variable(const string &name, const Type* t, const CVQualifiers* qfer) { - Variable *var = new Variable(name, 0, 0, qfer); + Variable *var = new Variable(name, t, 0, qfer); AllVars.push_back(var); return var; } diff --git a/src/VariableSelector.h b/src/VariableSelector.h index 845d7eb9f..6a479d9fa 100644 --- a/src/VariableSelector.h +++ b/src/VariableSelector.h @@ -43,6 +43,7 @@ class Expression; class Function; class Block; class Lhs; +class Fact; class CVQualifiers; class ArrayVariable; @@ -61,7 +62,7 @@ class VariableSelector public: VariableSelector(void) {}; static Variable* new_variable(const std::string &name, const Type *type, const Expression* init, const CVQualifiers* qfer); - static Variable *make_dummy_variable(const string &name, const CVQualifiers* qfer); + static Variable *make_dummy_variable(const string &name, const Type* t, const CVQualifiers* qfer); // ISSUE: use it only when you want to create a static variable static Variable *make_dummy_static_variable(const string &name); @@ -71,7 +72,7 @@ class VariableSelector eVariableScope scope=MAX_VAR_SCOPE); static Variable* choose_ok_var(const vector &vars); static const Variable* choose_ok_var(const vector &vars); - static const Variable* choose_visible_written_var(const Block* b, vector written_vars, const Type* type); + static const Variable* choose_visible_read_var(const Block* b, vector written_vars, const Type* type, const vector& facts); static Variable* choose_var(vector vars, Effect::Access access, const CGContext &cg_context, const Type* type, const CVQualifiers* qfer, eMatchType mt, const vector& invalid_vars, bool no_bitfield = false, bool no_expand_struct = false); @@ -148,8 +149,6 @@ class VariableSelector static bool is_eligible_var(const Variable* var, int deref_level, Effect::Access access, const CGContext& cg_context); - static void remove_non_qualified_vars(vector& vars, Effect::Access access, const CGContext &cg_context); - static Variable * create_and_initialize(Effect::Access access, const CGContext &cg_context, const Type* t, const CVQualifiers* qfer, Block *blk, std::string name); diff --git a/src/csmith.vcproj b/src/csmith.vcproj index 1b17855d7..d3615e310 100644 --- a/src/csmith.vcproj +++ b/src/csmith.vcproj @@ -734,6 +734,10 @@ /> + + @@ -1547,6 +1551,10 @@ RelativePath=".\FactPointTo.h" > + +