Expression * ExpressionFuncall::make_random(CGContext &cg_context, const Type* type, const CVQualifiers* qfer) { Expression *e = 0; bool std_func = ExpressionFunctionProbability(cg_context); ERROR_GUARD(NULL); // 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); ERROR_GUARD(NULL); 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; }
Expression * Expression::make_random_param(CGContext &cg_context, const Type* type, const CVQualifiers* qfer, enum eTermType tt) { DEPTH_GUARD_BY_TYPE_RETURN_WITH_FLAG(dtExpressionRandomParam, tt, NULL); Expression *e = 0; assert(type); // if a term type is provided, no need to choose random term type if (tt == MAX_TERM_TYPES) { VectorFilter filter(&Expression::paramTable_); filter.add(eConstant); // don't call functions with constant parameters because it is not interesting if ((!CGOptions::return_structs() && type->eType == eStruct) || (!CGOptions::return_unions() && type->eType == eUnion)) { filter.add(eFunction); } if (type->is_const_struct_union()) { filter.add(eAssignment); } if (cg_context.expr_depth + 2 > CGOptions::max_expr_depth()) { filter.add(eFunction).add(eAssignment).add(eCommaExpr); } tt = ExpressionTypeProbability(&filter); } ERROR_GUARD(NULL); switch (tt) { case eConstant: if (type->eType == eSimple) assert(type->simple_type != eVoid); e = HYPOTHESIS_DRAW(Constant, type); break; case eVariable: e = HYPOTHESIS_DRAW(ExpressionVariable, cg_context, type, qfer, true); break; case eFunction: e = HYPOTHESIS_DRAW(ExpressionFuncall, cg_context, type, qfer); break; case eAssignment: e = HYPOTHESIS_DRAW(ExpressionAssign, cg_context, type, qfer); break; case eCommaExpr: e = HYPOTHESIS_DRAW(ExpressionComma, cg_context, type, qfer); break; default: break; } if (e->term_type == eConstant || e->term_type == eVariable || (e->get_invoke() && e->get_invoke()->invoke_type == eFuncCall)) { cg_context.expr_depth++; } ERROR_GUARD(NULL); return e; }
static eTermType ExpressionTypeProbability(const VectorFilter *filter) { if (PartialExpander::direct_expand_check(eInvoke)) return eFunction; assert(filter); int i = rnd_upto(filter->get_max_prob(), filter); ERROR_GUARD(MAX_TERM_TYPES); return (eTermType)(filter->lookup(i)); }
int DFSRndNumGenerator::revisit_node(DFSRndNumGenerator::SearchState *state, int local_current_pos, int bound, const Filter *filter, const string *) { int rv = state->value(); if (filter) { if (rv >= bound) { state->dump(""); dumpCurrentState(bound, ""); cout << "rv = " << rv << ", bound = " << bound << std::endl; assert(0); } filter->filter(rv); ERROR_GUARD(-1); assert(current_pos_ < CGOptions::max_exhaustive_depth()); } seq_->add_number(rv, bound, local_current_pos); return rv; }
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; }
int DFSRndNumGenerator::random_choice (int bound, const Filter *filter, const string *where, vector<int> *invalid_nums) { int err = Error::get_error(); if (err == BACKTRACKING_ERROR) { return -1; } else if (err != SUCCESS) { assert("request random number in an error state. " && 0); } ++current_pos_; if (use_debug_sequence_) { int rv = seq_->get_number_by_pos(current_pos_); if (filter) filter->filter(rv); //cout << "current_pos _ = " << current_pos_ << ", length = " << seq_->sequence_length() << std::endl; if (static_cast<unsigned int>(current_pos_) >= seq_->sequence_length() - 1) { all_done_ = true; } return rv; } int local_current_pos = current_pos_; if (current_pos_ >= CGOptions::max_exhaustive_depth() || decision_depth_ >= CGOptions::max_exhaustive_depth()) { Error::set_error(EXCEED_MAX_DEPTH_ERROR); return -1; } DFSRndNumGenerator::SearchState *state = states_[current_pos_]; state->set_bound(bound); //dumpCurrentState(bound, ""); //state->dump(""); // Revisit a node if (current_pos_ < decision_depth_ && state->init()) { return revisit_node(state, local_current_pos, bound, filter, where); } if (state->init()) { int v = state->value(); int local_decision_depth = decision_depth_; do { // Filter out invalid value ++v; state->set_value(v); current_pos_ = local_current_pos; decision_depth_ = local_decision_depth; ERROR_GUARD(-1); } while (v < bound && ((filter && filter->filter(v)) || filter_invalid_nums(invalid_nums, v))); state->set_value(v); if (state->value() >= bound) { // backtracking current_pos_ = local_current_pos; for (int i = current_pos_; i < CGOptions::max_exhaustive_depth(); ++i) { states_[i]->set_init(false); } --decision_depth_; if (decision_depth_ < 0) all_done_ = true; Error::set_error(BACKTRACKING_ERROR); return -1; } else { // switch branch ERROR_GUARD(-1); int rv = state->value(); seq_->add_number(rv, bound, local_current_pos); return rv; } } else { // First time to visit this node int v = 0; ++decision_depth_; state->initSearchState(true, v, bound); while (v < bound && ((filter && (filter->filter(v))) || filter_invalid_nums(invalid_nums, v))) { // Filter out invalid value for (int i = decision_depth_; i < CGOptions::max_exhaustive_depth(); ++i) { states_[i]->set_value(0); } ERROR_GUARD(-1); decision_depth_ = current_pos_; current_pos_ = local_current_pos; ++v; } decision_depth_ = current_pos_; if (v >= bound) { current_pos_ = local_current_pos; for (int i = current_pos_; i < CGOptions::max_exhaustive_depth(); ++i) { states_[i]->set_init(false); } --decision_depth_; if (decision_depth_ < 0) all_done_ = true; Error::set_error(BACKTRACKING_ERROR); return -1; } state->set_value(v); ERROR_GUARD(-1); seq_->add_number(v, bound, local_current_pos); return v; } }
Expression * Expression::make_random(CGContext &cg_context, const Type* type, const CVQualifiers* qfer, bool no_func, bool no_const, enum eTermType tt) { DEPTH_GUARD_BY_TYPE_RETURN_WITH_FLAG(dtExpression, tt, NULL); Expression *e = 0; if (type == NULL) { do { type = cg_context.get_effect_context().is_side_effect_free() ? Type::choose_random_nonvoid() : Type::choose_random_nonvoid_nonvolatile(); } while (type->eType == eStruct && tt == eConstant); } assert(!(no_func && tt == eFunction)); assert(!(no_const && tt == eConstant)); // constant struct variables can not be a subexpression? assert(!(type->eType == eStruct && tt == eConstant)); // if no term type is provided, choose a random term type with restrictions if (tt == MAX_TERM_TYPES) { VectorFilter filter(&Expression::exprTable_); if (no_func || (!CGOptions::return_structs() && type->eType == eStruct) || (!CGOptions::return_unions() && type->eType == eUnion)) { filter.add(eFunction); } // struct constants can't be subexpressions (union constant can't either?) if (no_const || type->eType == eStruct || type->eType == eUnion) { filter.add(eConstant); } // can't assign to constant struct/unions. on the other hand, assign to a volatile // struct/union cause too much trouble for effect analysis, disable it for now if (type->is_const_struct_union() || type->is_volatile_struct_union()) { filter.add(eAssignment); } if (cg_context.expr_depth + 2 > CGOptions::max_expr_depth()) { filter.add(eFunction).add(eAssignment).add(eCommaExpr); } tt = ExpressionTypeProbability(&filter); } ERROR_GUARD(NULL); switch (tt) { case eConstant: if (type->eType == eSimple) assert(type->simple_type != eVoid); e = HYPOTHESIS_DRAW(Constant, type); break; case eVariable: e = HYPOTHESIS_DRAW(ExpressionVariable, cg_context, type, qfer); break; case eFunction: e = HYPOTHESIS_DRAW(ExpressionFuncall, cg_context, type, qfer); break; case eAssignment: e = HYPOTHESIS_DRAW(ExpressionAssign, cg_context, type, qfer); break; case eCommaExpr: e = HYPOTHESIS_DRAW(ExpressionComma, cg_context, type, qfer); break; default: break; } #if 0 if (!cg_context.get_effect_context().is_side_effect_free()) { assert(e->effect.is_side_effect_free()); } #endif // increment expression depth. A function call increase the depth by 1 if (e->term_type == eConstant || e->term_type == eVariable || (e->get_invoke() && e->get_invoke()->invoke_type == eFuncCall)) { cg_context.expr_depth++; } ERROR_GUARD(NULL); return e; }