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" > + +