Function * Function::make_first(void) { const Type *ty = RandomReturnType(); ERROR_GUARD(NULL); Function *f = new Function(RandomFunctionName(), ty); // dummy variable representing return variable, we don't care about the type, so use 0 string rvname = f->name + "_" + "rv"; CVQualifiers ret_qfer = CVQualifiers::random_qualifiers(ty); ERROR_GUARD(NULL); f->rv = Variable::CreateVariable(rvname, ty, NULL, &ret_qfer); // create a fact manager for this function, with empty global facts FactMgr* fm = new FactMgr(f); FMList.push_back(fm); ExtensionMgr::GenerateFirstParameterList(*f); // No Parameter List f->GenerateBody(CGContext::get_empty_context()); if (CGOptions::inline_function() && rnd_flipcoin(InlineFunctionProb)) f->is_inlined = true; fm->setup_in_out_maps(true); // update global facts to merged facts at all possible function exits fm->global_facts = fm->map_facts_out[f->body]; f->body->add_back_return_facts(fm, fm->global_facts); // collect info about global dangling pointers fm->find_dangling_global_ptrs(f); return f; }
StatementContinue * StatementContinue::make_random(CGContext &cg_context) { //static int g =0; FactMgr* fm = get_fact_mgr(&cg_context); // find the closest looping parent block: the one "continue" // would apply to //int h = g++; const Block* b = cg_context.get_current_block(); const Statement* prev_stm = b->get_last_stm(); // don't generate "continue" as the first statement in a block if (prev_stm == 0) { return 0; } while (b && !b->looping) { b = b->parent; } assert(b); cg_context.get_effect_stm().clear(); Expression *expr = HYPOTHESIS_DRAW(Expression, cg_context, get_int_type(), 0, true, true, eVariable); ERROR_GUARD(NULL); StatementContinue* sc = new StatementContinue(cg_context.get_current_block(), *expr, *b); fm->create_cfg_edge(sc, b, false, true); return sc; }
void StatementIf::combine_branch_facts(vector<const Fact*>& pre_facts) const { FactMgr* fm = get_fact_mgr_for_func(func); FactVec& outputs = fm->global_facts; fm->makeup_new_var_facts(pre_facts, fm->map_facts_out[&if_true]); fm->makeup_new_var_facts(pre_facts, fm->map_facts_out[&if_false]); bool true_must_return = if_true.must_return(); bool false_must_return = if_false.must_return(); // take return statement into consideration to achieve better precision if (true_must_return && false_must_return) { outputs = pre_facts; } else if (true_must_return) { // since false branch is created after true branch, it's output should // have all the variables created in true branch already outputs = fm->map_facts_out[&if_false]; } else if (false_must_return) { outputs = fm->map_facts_out[&if_true]; // if skip the outcome from false branch, don't forget facts of those variables // created in false branch fm->makeup_new_var_facts(outputs, fm->map_facts_in[&if_false]); } else { outputs = fm->map_facts_out[&if_true]; merge_facts(outputs, fm->map_facts_out[&if_false]); } }
/*************************************************************************************** * for a given input env, abstract a given statement, generate an output env, and * update both input/output env for this statement * * shortcut: if this input env matches previous input env, use previous output env directly ***************************************************************************************/ bool Statement::validate_and_update_facts(vector<const Fact*>& inputs, CGContext& cg_context) const { FactMgr* fm = get_fact_mgr_for_func(func); int shortcut = shortcut_analysis(inputs, cg_context); if (shortcut==0) { /* mark the goto statements inside this statement as visited this is to fix scenario like the following: lbl: s1 for (...) { goto lbl; } where the "for" statement is bypassed, but the output from "goto lbl" must be feed into s1 in order to achieve a fixed point */ for (size_t i=0; i<fm->cfg_edges.size(); i++) { const Statement* s = fm->cfg_edges[i]->src; if (s->eType == eGoto && contains_stmt(s)) { fm->map_visited[s] = true; } } return true; } if (shortcut==1) return false; vector<const Fact*> inputs_copy = inputs; if (!stm_visit_facts(inputs, cg_context)) { return false; } fm->set_fact_in(this, inputs_copy); fm->set_fact_out(this, inputs); return true; }
Expression * ExpressionFuncall::make_random(CGContext &cg_context, const Type* type, const TypeQualifiers* qfer) { Expression *e = 0; bool std_func = ExpressionFunctionProbability(cg_context); // unary/binary "functions" produce scalar types only if (type && (type->eType != eSimple || type->simple_type == eVoid)) std_func = false; Effect effect_accum = cg_context.get_accum_effect(); Effect effect_stm = cg_context.get_effect_stm(); FactMgr* fm = get_fact_mgr(&cg_context); vector<const Fact*> facts_copy = fm->global_facts; FunctionInvocation *fi = FunctionInvocation::make_random(std_func, cg_context, type, qfer); if (fi->failed) { // if it's a invalid invocation, (see FunctionInvocationUser::revisit) // restore the env, and replace invocation with a simple var cg_context.reset_effect_accum(effect_accum); cg_context.reset_effect_stm(effect_stm); fm->restore_facts(facts_copy); e = ExpressionVariable::make_random(cg_context, type, qfer); delete fi; } else { e = new ExpressionFuncall(*fi); } return e; }
/**************************************************************************** * Entry point to pointer analysis and other DFA analysis for newly * created statement. remember some analysis has already been done during the * statement generation, some analysis work is only possible with a complete * statement, we do it here ****************************************************************************/ void Statement::post_creation_analysis(vector<const Fact*>& pre_facts, const Effect& pre_effect, CGContext& cg_context) const { FactMgr* fm = get_fact_mgr_for_func(func); if (eType == eIfElse) { ((const StatementIf*)this)->combine_branch_facts(pre_facts); } else { fm->makeup_new_var_facts(pre_facts, fm->global_facts); } // save the effect for this statement if this is a simple statement // for compound statements, it's effect is saved in make_random if (!is_compound(eType)) { fm->map_stm_effect[this] = cg_context.get_effect_stm(); } bool special_handled = false; // special handling for non-looping statements in func_1, which we never re-visit to // save run-time if (cg_context.get_current_func()->name == "func_1" && !(cg_context.flags & IN_LOOP) ) { if (has_uncertain_call_recursive()) { FactVec outputs = pre_facts; cg_context.reset_effect_accum(pre_effect); //if (stm_id == 573) /*if (this->eType == eAssign) { ((const StatementAssign*)this)->get_rhs()->indented_output(cout, 0); } cout << endl; Output(cout, fm);*/ //} if (!validate_and_update_facts(outputs, cg_context)) { assert(0); } fm->global_facts = outputs; special_handled = true; } } if (!special_handled) { // for if...else..., we don't want to walk through the true branch and false branch again // compute the output with consideration of return statement(s) in both branches if (eType == eAssign) { const StatementAssign* sa = (const StatementAssign*)this; // abstract fact for assignment itself. No analysis on function calls // on RHS since they are already handled during statement generation FactMgr::update_fact_for_assign(sa, fm->global_facts); } else if (eType == eReturn) { const StatementReturn* sr = (const StatementReturn*)this; FactMgr::update_fact_for_return(sr, fm->global_facts); } } fm->remove_rv_facts(fm->global_facts); fm->set_fact_in(this, pre_facts); fm->set_fact_out(this, fm->global_facts); fm->map_accum_effect[this] = *(cg_context.get_effect_accum()); fm->map_visited[this] = true; }
/************************************************************************************************** * DFA analysis for a block: * * we must considers all kinds of blocks: block for for-loops; block for if-true and if-false; block for * function body; block that loops; block has jump destination insdie; block being a jump destination itself * (in the case of "continue" in for-loops). All of them must be taken care in this function. * * params: * inputs: the inputs env before entering block * cg_context: code generation context * fail_index: records which statement in this block caused analyzer to fail * visit_one: when is true, the statements in this block must be visited at least once ****************************************************************************************************/ bool Block::find_fixed_point(vector<const Fact*> inputs, vector<const Fact*>& post_facts, CGContext& cg_context, int& fail_index, bool visit_once) const { 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<const CFGEdge*> edges; int cnt = 0; do { // if we have never visited the block, force the visitor to go through all statements at least once if (fm->map_visited[this]) { if (cnt++ > 7) { // takes too many iterations to reach a fixed point, must be something wrong assert(0); } find_edges_in(edges, false, true); for (i=0; i<edges.size(); i++) { const Statement* src = edges[i]->src; //assert(fm->map_visited[src]); merge_facts(inputs, fm->map_facts_out[src]); } } if (!visit_once) { int shortcut = shortcut_analysis(inputs, cg_context); if (shortcut == 0) return true; } //if (shortcut == 1) return false; FactVec outputs = inputs; // add facts for locals for (i=0; i<local_vars.size(); i++) { const Variable* v = local_vars[i]; FactMgr::add_new_var_fact(v, outputs); } // revisit statements with new inputs for (i=0; i<stms.size(); i++) { int h = g++; if (h == 2585) BREAK_NOP; // for debugging if (!stms[i]->analyze_with_edges_in(outputs, cg_context)) { fail_index = i; return false; } } fm->set_fact_in(this, inputs); post_facts = outputs; FactMgr::update_facts_for_oos_vars(local_vars, outputs); fm->set_fact_out(this, outputs); fm->map_visited[this] = true; // compute accumulated effect set_accumulated_effect(cg_context); visit_once = false; } while (true); return true; }
StatementIf * StatementIf::make_random(CGContext &cg_context) { DEPTH_GUARD_BY_TYPE_RETURN(dtStatementIf, NULL); FactMgr* fm = get_fact_mgr(&cg_context); FactVec pre_facts; Effect pre_effect; // func_1 hacking, save the env in case we need to re-analyze if (cg_context.get_current_func()->name == "func_1" && !(cg_context.flags & IN_LOOP)) { pre_effect = cg_context.get_accum_effect(); pre_facts = fm->global_facts; } cg_context.get_effect_stm().clear(); Expression *expr = Expression::make_random(cg_context, get_int_type(), NULL, false, !CGOptions::const_as_condition()); ERROR_GUARD(NULL); // func_1 hacking, re-analyze for multiple function calls if (cg_context.get_current_func()->name == "func_1" && !(cg_context.flags & IN_LOOP)) { if (expr->has_uncertain_call_recursive()) { fm->makeup_new_var_facts(pre_facts, fm->global_facts); cg_context.reset_effect_accum(pre_effect); cg_context.curr_blk = cg_context.get_current_block(); bool ok = expr->visit_facts(pre_facts, cg_context); if (!ok) { // print_facts(pre_facts); // expr->indented_output(cout, 0); } assert(ok); fm->global_facts = pre_facts; } } Effect eff = cg_context.get_effect_stm(); // this will save global_facts to map_facts_in[if_true], and update // facts for new variables created while generating if_true Block *if_true = Block::make_random(cg_context); ERROR_GUARD_AND_DEL1(NULL, expr); // generate false branch with the same env as true branch fm->global_facts = fm->map_facts_in[if_true]; Block *if_false = Block::make_random(cg_context); ERROR_GUARD_AND_DEL2(NULL, expr, if_true); 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); return si; }
void FactMgr::update_fact_for_return(const StatementReturn* sr, FactVec& inputs) { size_t i, j; for (i=0; i<FactMgr::meta_facts.size(); i++) { std::vector<const Fact*> facts = FactMgr::meta_facts[i]->abstract_fact_for_return(inputs, sr->get_var(), sr->func); for (j=0; j<facts.size(); j++) { // merge with other return statements if (merge_fact(inputs, facts[j])) { sr->func->fact_changed = true; } } } // incorporate current facts into return facts FactMgr* fm = get_fact_mgr_for_func(sr->func); fm->set_fact_out(sr, inputs); }
Block * Block::make_dummy_block(CGContext &cg_context) { Function *curr_func = cg_context.get_current_func(); assert(curr_func); Block *b = new Block(cg_context.get_current_block(), 0); b->func = curr_func; b->in_array_loop = !(cg_context.iv_bounds.empty()); curr_func->blocks.push_back(b); curr_func->stack.push_back(b); FactMgr* fm = get_fact_mgr_for_func(curr_func); fm->set_fact_in(b, fm->global_facts); Effect pre_effect = cg_context.get_accum_effect(); b->post_creation_analysis(cg_context, pre_effect); curr_func->stack.pop_back(); return b; }
void StatementFor::post_loop_analysis(CGContext& cg_context, vector<const Fact*>& pre_facts, Effect& pre_effect) { FactMgr* fm = get_fact_mgr(&cg_context); assert(fm); // if the control reached the end of this for-loop with must-return body, it means // the loop is never entered. restore facts to pre-loop env fm->global_facts = fm->map_facts_in[&body]; if (body.must_return()) { fm->restore_facts(pre_facts); } // add forward edges introduced by "break" for (size_t i=0; i<body.break_stms.size(); i++) { const StatementBreak* stm = dynamic_cast<const StatementBreak*>(body.break_stms[i]); fm->create_cfg_edge(stm, this, true, false); FactMgr::merge_jump_facts(fm->global_facts, fm->map_facts_out[stm]); } // compute accumulated effect set_accumulated_effect_after_block(pre_effect, &body, cg_context); }
bool Statement::stm_visit_facts(vector<const Fact*>& inputs, CGContext& cg_context) const { cg_context.get_effect_stm().clear(); cg_context.curr_blk = parent; FactMgr* fm = get_fact_mgr(&cg_context); //static int g = 0; //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; }
Statement* Block::append_return_stmt(CGContext& cg_context) { FactMgr* fm = get_fact_mgr_for_func(func); FactVec pre_facts = fm->global_facts; cg_context.get_effect_stm().clear(); Statement* sr = Statement::make_random(cg_context, eReturn); ERROR_GUARD(NULL); stms.push_back(sr); fm->makeup_new_var_facts(pre_facts, fm->global_facts); assert(sr->visit_facts(fm->global_facts, cg_context)); fm->set_fact_in(sr, pre_facts); fm->set_fact_out(sr, fm->global_facts); fm->map_accum_effect[sr] = *(cg_context.get_effect_accum()); fm->map_visited[sr] = true; //sr->post_creation_analysis(pre_facts, cg_context); fm->map_accum_effect[this] = *(cg_context.get_effect_accum()); fm->map_stm_effect[this].add_effect(fm->map_stm_effect[sr]); return sr; }
/********************************************************************** * once generated the loop body, verify whether some statement caused * the analyzer to fail during the 2nd iteration of the loop body (in * most case, a null/dead pointer dereference would do it), if so, delete * the statement in which analyzer fails and all subsequent statemets * * also performs effect analysis *********************************************************************/ void Block::post_creation_analysis(CGContext& cg_context, const Effect& pre_effect) { int index; FactMgr* fm = get_fact_mgr(&cg_context); fm->map_visited[this] = true; // compute accumulated effect set_accumulated_effect(cg_context); //fm->print_facts(fm->global_facts); vector<const Fact*> post_facts = fm->global_facts; FactMgr::update_facts_for_oos_vars(local_vars, fm->global_facts); fm->remove_rv_facts(fm->global_facts); fm->set_fact_out(this, fm->global_facts); // find out if fixed-point-searching is required bool is_loop_body = !must_break_or_return() && looping; bool self_back_edge = false; if (is_loop_body || need_revisit || has_edge_in(false, true)) { if (is_loop_body && from_tail_to_head()) { self_back_edge = true; fm->create_cfg_edge(this, this, false, true); } vector<const Fact*> facts_copy = fm->map_facts_in[this]; // reset the accumulative effect cg_context.reset_effect_accum(pre_effect); while (!find_fixed_point(facts_copy, post_facts, cg_context, index, need_revisit)) { size_t i, len; len = stms.size(); for (i=index; i<len; i++) { remove_stmt(stms[i]); i = index-1; len = stms.size(); } // if we delete some statements, next visit must go through statements (no shortcut) need_revisit = true; // clean up in/out map from previous analysis that might include facts caused by deleted statements fm->reset_stm_fact_maps(this); // sometimes a loop would emerge after we delete the "return" statement in body if (!self_back_edge && from_tail_to_head()) { self_back_edge = true; fm->create_cfg_edge(this, this, false, true); } // reset incoming effects cg_context.reset_effect_accum(pre_effect); } fm->global_facts = fm->map_facts_out[this]; } // make sure we add back return statement for blocks that require it and had such statement deleted // only do this for top-level block of a function which requires a return statement if (parent == 0 && func->need_return_stmt() && !must_return()) { fm->global_facts = post_facts; Statement* sr = append_return_stmt(cg_context); fm->set_fact_out(this, fm->map_facts_out[sr]); } }
void Function::make_builtin_function(const string &function_string) { vector<string> v; StringUtils::split_string(function_string, v, ";"); if (v.size() == 4) { if (!CGOptions::enabled_builtin(v[3])) return; } else if (v.size() == 3) { if (!CGOptions::enabled_builtin("generic")) return; } else { assert(0 && "Invalid builtin function format!"); } const Type *ty = Type::get_type_from_string(v[0]); Function *f = new Function(v[1], ty, /*is_builtin*/true); // dummy variable representing return variable, we don't care about the type, so use 0 string rvname = f->name + "_" + "rv"; CVQualifiers ret_qfer = CVQualifiers::random_qualifiers(ty); f->rv = Variable::CreateVariable(rvname, ty, NULL, &ret_qfer); // create a fact manager for this function, with empty global facts FactMgr* fm = new FactMgr(f); FMList.push_back(fm); GenerateParameterListFromString(*f, StringUtils::get_substring(v[2], '(', ')')); f->GenerateBody(CGContext::get_empty_context()); // update global facts to merged facts at all possible function exits fm->global_facts = fm->map_facts_out[f->body]; f->body->add_back_return_facts(fm, fm->global_facts); // collect info about global dangling pointers fm->find_dangling_global_ptrs(f); ++builtin_functions_cnt; }
Statement* Block::append_nested_loop(CGContext& cg_context) { FactMgr* fm = get_fact_mgr_for_func(func); FactVec pre_facts = fm->global_facts; cg_context.get_effect_stm().clear(); Statement* sf = HYPOTHESIS_DRAW(Statement, cg_context, eFor); ERROR_GUARD(NULL); stms.push_back(sf); fm->makeup_new_var_facts(pre_facts, fm->global_facts); //assert(sf->visit_facts(fm->global_facts, cg_context)); fm->set_fact_in(sf, pre_facts); fm->set_fact_out(sf, fm->global_facts); fm->map_accum_effect[sf] = *(cg_context.get_effect_accum()); fm->map_visited[sf] = true; //sf->post_creation_analysis(pre_facts, cg_context); fm->map_accum_effect[this] = *(cg_context.get_effect_accum()); fm->map_stm_effect[this].add_effect(fm->map_stm_effect[sf]); return sf; }
FunctionInvocation * FunctionInvocation::make_random_binary(CGContext &cg_context, const Type* type) { DEPTH_GUARD_BY_TYPE_RETURN(dtFunctionInvocationRandomBinary, NULL); if (rnd_flipcoin(10) && Type::has_pointer_type() && type->eType != eVector) { ERROR_GUARD(NULL); return make_random_binary_ptr_comparison(cg_context); } eBinaryOps op = (eBinaryOps)(rnd_upto(MAX_BINARY_OP, BINARY_OPS_PROB_FILTER)); ERROR_GUARD(NULL); assert(type); SafeOpFlags *flags = SafeOpFlags::make_random(sOpBinary, op); assert(flags); ERROR_GUARD(NULL); // Special stuff for vectors. if (type->eType == eVector) { // Only signed type can use logicals. Also no div or mod. // TODO: Instead of changing the op, flip the sign of the type. if (!type->is_signed() && ( op==eCmpGt || op==eCmpLt || op==eCmpGe || op==eCmpLe || op==eCmpEq || op==eCmpNe || op==eAnd || op==eOr || op==eDiv || op==eMod)) { op = eAdd; } // Only unsigned can use unsafe ops. if (type->is_signed() && ( op==eAdd || op==eSub || op==eMul || op==eDiv || op==eMod || op==eRShift || op==eLShift)) { op = eAnd; } delete flags; flags = SafeOpFlags::make_dummy_flags(); } FunctionInvocationBinary *fi = FunctionInvocationBinary::CreateFunctionInvocationBinary(cg_context, op, flags); Effect lhs_eff_accum; CGContext lhs_cg_context(cg_context, cg_context.get_effect_context(), &lhs_eff_accum); // Generate an expression with the correct type required by safe math operands const Type* lhs_type = flags->get_lhs_type(); const Type* rhs_type = flags->get_rhs_type(); // More special stuff for vectors. if (type->eType == eVector) { lhs_type = type; rhs_type = type; } assert(lhs_type && rhs_type); Expression *lhs = Expression::make_random(lhs_cg_context, lhs_type); ERROR_GUARD_AND_DEL1(NULL, fi); Expression *rhs = 0; cg_context.merge_param_context(lhs_cg_context, true); FactMgr* fm = get_fact_mgr(&cg_context); vector<const Fact*> facts_copy = fm->global_facts; #if 0 if (lhs->term_type == eVariable) { lhs_eff_accum.read_deref_volatile((ExpressionVariable*)lhs); } #endif // If we are guaranteed that the LHS will be evaluated before the RHS, // or if the LHS is pure (not merely side-effect-free), // then we can generate the RHS under the original effect context. if (IsOrderedStandardFunc(op)) { // || lhs_eff_accum.is_pure()) { TODO: need more thoughts on the purity issue. rhs = Expression::make_random(cg_context, rhs_type); } else { // Otherwise, the RHS must be generated under the combined effect // of the original effect and the LHS effect. Effect rhs_eff_context(cg_context.get_effect_context()); rhs_eff_context.add_effect(lhs_eff_accum, true); Effect rhs_eff_accum; CGContext rhs_cg_context(cg_context, rhs_eff_context, &rhs_eff_accum); if (op == eLShift || op == eRShift) { eTermType tt = MAX_TERM_TYPES; bool not_constant = rnd_flipcoin(ShiftByNonConstantProb); // avoid shifting negative or too much if (!not_constant) { rhs = lhs_type->eType == eVector ? dynamic_cast<Expression*>(CLSmith::ExpressionVector::make_constant(rhs_type, lhs_type->SizeInBytes() * 8)) : dynamic_cast<Expression*>(Constant::make_random_upto(lhs_type->SizeInBytes() * 8)); } else { rhs = Expression::make_random(rhs_cg_context, rhs_type, NULL, false, true, tt); } } else { rhs = Expression::make_random(rhs_cg_context, rhs_type); // avoid divide by zero or possible zero (reached by pointer comparison) if ((op == eMod || op == eDiv) && (rhs->equals(0) || rhs->is_0_or_1())) { VectorFilter f; f.add(eMod).add(eDiv).add(eLShift).add(eRShift); op = (eBinaryOps)(rnd_upto(MAX_BINARY_OP, &f)); fi->set_operation(op); } } cg_context.merge_param_context(rhs_cg_context, true); } ERROR_GUARD_AND_DEL2(NULL, fi, lhs); if (CompatibleChecker::compatible_check(lhs, rhs)) { Error::set_error(COMPATIBLE_CHECK_ERROR); delete lhs; delete rhs; delete fi; return NULL; } // ordered operators such as "||" or "&&" may skip the 2nd parameter if (IsOrderedStandardFunc(op)) { fm->makeup_new_var_facts(facts_copy, fm->global_facts); merge_facts(fm->global_facts, facts_copy); } // TODO: fix `rhs' for eLShift and eRShift and ... // Currently, the "fix" is handled in `FunctionInvocationBinary::Output'. fi->param_value.push_back(lhs); fi->param_value.push_back(rhs); return fi; }
Block * Block::make_random(CGContext &cg_context, bool looping) { //static int bid = 0; DEPTH_GUARD_BY_TYPE_RETURN(dtBlock, NULL); Function *curr_func = cg_context.get_current_func(); assert(curr_func); Block *b = new Block(cg_context.get_current_block(), CGOptions::max_block_size()); b->func = curr_func; 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()); //b->stm_id = bid++; // Push this block onto the variable scope stack. curr_func->stack.push_back(b); curr_func->blocks.push_back(b); // record global facts at this moment so that subsequent statement // inside the block doesn't ruin it FactMgr* fm = get_fact_mgr_for_func(curr_func); fm->set_fact_in(b, fm->global_facts); Effect pre_effect = cg_context.get_accum_effect(); unsigned int max = BlockProbability(*b); if (Error::get_error() != SUCCESS) { curr_func->stack.pop_back(); delete b; return NULL; } unsigned int i; if (b->stm_id == 1) BREAK_NOP; // for debugging for (i = 0; i <= max; ++i) { Statement *s = HYPOTHESIS_DRAW(Statement, cg_context); // In the exhaustive mode, Statement::make_random could return NULL; if (!s) break; b->stms.push_back(s); if (s->must_return()) { break; } } if (Error::get_error() != SUCCESS) { curr_func->stack.pop_back(); delete b; return NULL; } // append nested loop if some must-read/write variables hasn't been accessed if (b->need_nested_loop(cg_context) && cg_context.blk_depth < CGOptions::max_blk_depth()) { b->append_nested_loop(cg_context); } // perform DFA analysis after creation b->post_creation_analysis(cg_context, pre_effect); if (Error::get_error() != SUCCESS) { curr_func->stack.pop_back(); delete b; return NULL; } curr_func->stack.pop_back(); if (Error::get_error() != SUCCESS) { //curr_func->stack.pop_back(); delete b; return NULL; } // ISSUE: in the exhaustive mode, do we need a return statement here // if the last statement is not? Error::set_error(SUCCESS); return b; }