Ejemplo n.º 1
0
const Variable*
StatementFor::make_iteration(CGContext& cg_context, StatementAssign*& init, Expression*& test, StatementAssign*& incr, unsigned int& bound)
{
	FactMgr* fm = get_fact_mgr(&cg_context);
	assert(fm);
	Block* blk = cg_context.get_current_block();
	assert(blk);

	// save a copy of facts env and context
	vector<const Fact*> facts_copy = fm->global_facts;
	cg_context.get_effect_stm().clear();

	// Select the loop control variable, avoid volatile
	vector<const Variable*> invalid_vars;
	Variable *var = NULL;
	do {
		var = VariableSelector::SelectLoopCtrlVar(cg_context, invalid_vars);
		ERROR_GUARD(NULL);
		if (var->is_volatile()) {
			invalid_vars.push_back(var);
		} else {
			break;
		}
	} while (true);

	bool read = cg_context.read_indices(var, fm->global_facts);
	assert(read);
	cg_context.write_var(var);
	cg_context.read_var(var);

	// Select the loop parameters: init, limit, increment, etc.
	int        init_n, limit_n, incr_n;
	eBinaryOps test_op;
	eAssignOps incr_op;
	bound = INVALID_BOUND;

	// choose a random array from must use variables, and find the dimension with shortest length
	// JYTODO: be more aggressive?
	if (cg_context.rw_directive) {
		vector<const Variable*> arrays;
		cg_context.rw_directive->find_must_use_arrays(arrays);
		if (!arrays.empty()) {
			const ArrayVariable* av = dynamic_cast<const ArrayVariable*>(VariableSelector::choose_ok_var(arrays));
			assert(av);
			for (size_t i=0; i<av->get_dimension(); i++) {
				if (av->get_sizes()[i] < bound) {
					bound = av->get_sizes()[i];
				}
			}
		}
	}
	if (bound != INVALID_BOUND) {
		bound = make_random_array_control(--bound, init_n, limit_n, incr_n, test_op, incr_op, var->type->is_signed());
	} else {
		assert(var->type);
		make_random_loop_control(init_n, limit_n, incr_n, test_op, incr_op, var->type->is_signed());
	}
	ERROR_GUARD(NULL);

	// Build the IR for the subparts of the loop.
	Constant * c_init = Constant::make_int(init_n);
	ERROR_GUARD(NULL);

	// if we chose control variable wisely, this should never return false
	assert(var);
	Lhs* lhs = new Lhs(*var);
	ERROR_GUARD_AND_DEL1(NULL, c_init);
	eBinaryOps bop = StatementAssign::compound_to_binary_ops(incr_op);
	SafeOpFlags *flags1 = SafeOpFlags::make_random_binary(var->type, var->type, var->type, sOpAssign, bop);
	ERROR_GUARD_AND_DEL2(NULL, c_init, lhs);

	init = new StatementAssign(cg_context.get_current_block(), *lhs, *c_init, eSimpleAssign, flags1);
	ERROR_GUARD_AND_DEL3(NULL, c_init, lhs, flags1);
	bool visited = init->visit_facts(fm->global_facts, cg_context);
	assert(visited);

	assert(var);
	ExpressionVariable *v = new ExpressionVariable(*var);
	Bookkeeper::record_volatile_access(v->get_var(), v->get_indirect_level(), false);
	Bookkeeper::record_volatile_access(v->get_var(), v->get_indirect_level(), true);

	Constant *c_limit = Constant::make_int(limit_n);
	ERROR_GUARD_AND_DEL2(NULL, init, v);

	FunctionInvocation *invocation = FunctionInvocation::make_binary(cg_context, test_op, v, c_limit);
	ERROR_GUARD_AND_DEL3(NULL, init, v, c_limit);

	test = new ExpressionFuncall(*invocation);

	// canonize before validation
	//const ExpressionVariable exp_var(*var);
	//const FunctionInvocationBinary fb(eAdd, &exp_var, c_incr);
	//const ExpressionFuncall funcall(fb);
	Lhs *lhs1 = dynamic_cast<Lhs*>(lhs->clone());
	//SafeOpFlags *flags2 = SafeOpFlags::make_random(sOpAssign);
	ERROR_GUARD_AND_DEL3(NULL, init, test, lhs1);

	Constant * c_incr = Constant::make_int(incr_n);
	ERROR_GUARD_AND_DEL3(NULL, init, test, lhs1);

	if (bound != INVALID_BOUND) {
		incr = new StatementAssign(cg_context.get_current_block(), *lhs1, *c_incr, incr_op);
	} else {
		incr = StatementAssign::make_possible_compound_assign(cg_context, &(v->get_type()), *lhs1, incr_op, *c_incr);
	}
	return var;
}
Ejemplo n.º 2
0
ExpressionVariable *
ExpressionVariable::make_random(CGContext &cg_context, const Type* type, const CVQualifiers* qfer, bool as_param, bool as_return)
{
	DEPTH_GUARD_BY_TYPE_RETURN(dtExpressionVariable, NULL);
	Function *curr_func = cg_context.get_current_func(); 
	FactMgr* fm = get_fact_mgr_for_func(curr_func);
	vector<const Variable*> dummy; 

	// save current effects, in case we need to reset 
	Effect eff_accum = cg_context.get_accum_effect();
	Effect eff_stmt = cg_context.get_effect_stm();
  
	ExpressionVariable *ev = 0;
	do {
		const Variable* var = 0; 
		// try to use one of must_read_vars in CGContext 
		var = VariableSelector::select_must_use_var(Effect::READ, cg_context, type, qfer);  
		if (var == NULL) {
			var = VariableSelector::select(Effect::READ, cg_context, type, qfer, dummy, eFlexible);
		}
		ERROR_GUARD(NULL);
		if (!var) 
			continue;
		if (!type->is_float() && var->type->is_float())
			continue;
		// forbid a parameter to take the address of an argument
		// this is to simplify the path shortcutting delta
		if (as_param && var->is_argument() && var->type->is_dereferenced_from(type)) {
			continue;
		}
		if (!CGOptions::addr_taken_of_locals()
			&& var->type->is_dereferenced_from(type)
			&& (var->is_argument() || var->is_local())) {
			continue;
		}

		// forbid a escaping pointer to take the address of an argument or a local variable
		int indirection = var->type->get_indirect_level() - type->get_indirect_level();
		if (as_return && CGOptions::no_return_dead_ptr() &&
			FactPointTo::is_pointing_to_locals(var, cg_context.get_current_block(), indirection, fm->global_facts)) {
			continue;
		}
		int valid = FactPointTo::opportunistic_validate(var, type, fm->global_facts);
		if (valid) {
			ExpressionVariable tmp(*var, type);
			if (tmp.visit_facts(fm->global_facts, cg_context)) { 
				ev = tmp.get_indirect_level() == 0 ? new ExpressionVariable(*var) : new ExpressionVariable(*var, type); 
				cg_context.curr_blk = cg_context.get_current_block();
				break;
			}  
			else {
				cg_context.reset_effect_accum(eff_accum);
				cg_context.reset_effect_stm(eff_stmt);
			}
		}
		dummy.push_back(var);
	} while (true);

	// statistics
	int deref_level = ev->get_indirect_level();
	if (deref_level > 0) {
		incr_counter(Bookkeeper::read_dereference_cnts, deref_level); 
	}
	if (deref_level < 0) {
		Bookkeeper::record_address_taken(ev->get_var());
	}   
	Bookkeeper::record_volatile_access(ev->get_var(), deref_level, false);
	return ev;
}