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;
          }
        }
      }
    }
  }
Beispiel #2
0
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;
}