Exemple #1
0
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]);
	}
}
Exemple #4
0
/***************************************************************************************
 * 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;
}
Exemple #5
0
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;
}
Exemple #6
0
/****************************************************************************
 * 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;
}
Exemple #9
0
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;
}
Exemple #11
0
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);
}
Exemple #12
0
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;
}
Exemple #13
0
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]);
	}
}
Exemple #15
0
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;
}