void MultiMap(Exp *exp, Vector<Exp*> *res) { // follow possible equalities for lvalues and non-arithmetic binops // appearing in the input formula. bool handle_exp = false; if (exp->IsLvalue() || exp->IsBound() || exp->IsTerminate()) handle_exp = true; else if (ExpBinop *nexp = exp->IfBinop()) { switch (nexp->GetBinopKind()) { case B_Mod: case B_BitwiseAnd: case B_BitwiseOr: case B_BitwiseXOr: case B_Min: case B_Max: handle_exp = true; default: break; } } /* // special cased constant substitution. if we see an 'n < val' // or 'n+1 <= val' and a comparison 'n+1 ~ oval', try substituting // 'oval <= val'. if (ExpBinop *nexp = exp->IfBinop()) { long left_value, right_value; BinopKind kind = nexp->GetBinopKind(); Exp *left = nexp->GetLeftOperand(); Exp *right = nexp->GetRightOperand(); if ((kind == B_LessThan || kind == B_LessEqual) && left->IsInt() && left->AsInt()->GetInt(&left_value)) { for (size_t ind = 0; ind < equalities.Size(); ind++) { const BaseCompare &equality = equalities[ind]; if (equality.target->IsInt() && equality.target->AsInt()->GetInt(&right_value) && right_value == left_value + (kind == B_LessThan ? 1 : 0)) { Exp *new_exp = Exp::MakeBinop(B_LessEqual, equality.source, right); ExpAddResult(new_exp, res); } } } } */ if (!handle_exp) { ExpAddResult(exp, res); return; } bool is_loop = (mcfg->GetId()->Kind() == B_Loop); // for loops, only follow equalities for terms which change with // each iteration. if (is_loop && mcfg->IsExpPreserved(exp)) { ExpAddResult(exp, res); return; } ExpAddResult(exp, res); // try to substitute the expression for anything it might share // an ==/<=/>= relationship with. for (size_t ind = 0; ind < equalities.Size(); ind++) { const BaseCompare &equality = equalities[ind]; // watch for recursion when following compares. if (expand_stack.Contains(equality.test)) continue; // check if there is a match between the exp and equality source. Exp *new_target = MatchEquality(exp, equality); if (new_target) { // keep track of the tests we use during recursive mapping. expand_stack.PushBack(equality.test); // list to hold result of mapping this substitution. Vector<Exp*> sub_res; EqualityMapper sub_mapper(mcfg, verbose, equalities, expand_stack); new_target->DoMultiMap(&sub_mapper, &sub_res); expand_stack.PopBack(); // for functions, filter out substitutions which resulted in an // increase in the number of leaf terms in the expression. this both // gets rid of results we don't care about and prevents exponential // blowup. we don't need to worry about this for loops because // we only follow substitutions for values which change in each // iteration, a similar (and less crude) filtering. size_t base_term_count = exp->TermCount(); if (verbose) logout << "SUFFICIENT: Substituted: " << exp << " [" << sub_res.Size() << "]" << endl; for (size_t rind = 0; rind < sub_res.Size(); rind++) { Exp *res_exp = sub_res[rind]; if (is_loop || res_exp->TermCount() <= base_term_count) { if (verbose) logout << " Added: " << res_exp << endl; ExpAddResult(res_exp, res); } else { if (verbose) logout << " Dropped: " << res_exp << endl; } } } } }
Where* CheckerPropagate::TryPropagate(Bit *bit, Exp *lval) { BlockMemory *mcfg = m_frame->Memory(); TypeCSU *csu = NULL; Exp *csu_lval = NULL; if (UseHeapExp(lval, &csu, &csu_lval)) { // do the heap propagation unless we are trying to push heap data // up into the caller. if (!m_prefer_precondition || !UseCallerExp(lval, m_frame->Kind() == B_Function) || (m_frame->Kind() == B_Loop && !mcfg->IsExpPreserved(lval))) { Where *res = WhereInvariant::Make(csu, csu_lval, bit); if (res) return res; // fall through, we might still be able to treat this as a precondition. } } if (UseCallerExp(lval, m_frame->Kind() == B_Function)) return WherePrecondition::Make(m_frame->Memory(), bit); if (PPoint point = UseCalleeExp(lval)) { // fail propagation if this is from a later callee than the point // this propagation occurs at. this can come up when generating // sufficient conditions. if (point > m_point || (point == m_point && !m_allow_point)) return NULL; // cutoff propagation if the buffer came from a primitive memory // allocator. if we find a sufficient condition that does not // mention the allocator we could continue propagation. PEdge *edge = mcfg->GetCFG()->GetSingleOutgoingEdge(point); PEdgeCall *edge_call = edge->IfCall(); Variable *callee = edge_call ? edge_call->GetDirectFunction() : NULL; Exp *callee_base; Exp *callee_size; if (callee && GetAllocationFunction(callee, &callee_base, &callee_size)) { callee_base->DecRef(); callee_size->DecRef(); if (lval->IsBound()) lval = lval->GetLvalTarget(); // ignore this if it refers to fields or other structures // in the result of the allocation. this data is either // uninitialized or zeroed, either way we don't care. if (ExpClobber *nlval = lval->IfClobber()) { Exp *callee_lval = nlval->GetCallee(); Exp *callee_target = NULL; if (nlval->GetValueKind() == NULL) { callee_target = callee_lval; } else { // skip the first dereference. for terminators we still depend on // the initial contents of the allocated buffer. if (ExpExit *ncallee = callee_lval->IfExit()) callee_target = ncallee->GetTarget(); } if (callee_target) { while (callee_target->IsFld()) callee_target = callee_target->GetLvalTarget(); if (callee_target->IsExit()) return new WhereNone(RK_None); } } // watch for accessing indexes of a buffer returned via the allocator, // which currently aren't mapped back into the callee correctly. // TODO: fix hack. if (lval->IsDrf() && lval->GetLvalTarget()->IsIndex()) return new WhereNone(RK_None); return new WhereNone(RK_Finished); } if (callee && IsCutoffFunction(callee)) return new WhereNone(RK_Finished); return WherePostcondition::Make(m_frame, point, bit); } return NULL; }