Ejemplo n.º 1
0
void BlockSummary::GetAssumedBits(BlockMemory *mcfg, PPoint end_point,
                                  Vector<AssumeInfo> *assume_list)
{
  BlockId *id = mcfg->GetId();
  BlockCFG *cfg = mcfg->GetCFG();

  BlockSummary *sum = GetBlockSummary(id);

  const Vector<Bit*> *assumes = sum->GetAssumes();
  size_t assume_count = VectorSize<Bit*>(assumes);

  // pull in assumptions from the summary for mcfg. in some cases these
  // assumptions won't be useful, e.g. describing the state at exit
  // for functions. for now we're just adding all of them though. TODO: fix.
  for (size_t ind = 0; ind < assume_count; ind++) {
    Bit *bit = assumes->At(ind);
    bit->IncRef(assume_list);

    AssumeInfo info;
    info.bit = bit;
    assume_list->PushBack(info);
  }

  sum->DecRef();

  Vector<BlockCFG*> *annot_list = BodyAnnotCache.Lookup(id->Function());

  // add assumes at function entry for any preconditions.

  if (id->Kind() == B_Function) {
    for (size_t ind = 0; annot_list && ind < annot_list->Size(); ind++) {
      BlockCFG *annot_cfg = annot_list->At(ind);

      if (annot_cfg->GetAnnotationKind() != AK_Precondition &&
          annot_cfg->GetAnnotationKind() != AK_PreconditionAssume)
        continue;

      Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg);
      if (!bit) continue;

      annot_cfg->IncRef(assume_list);
      bit->IncRef(assume_list);

      AssumeInfo info;
      info.annot = annot_cfg;
      info.bit = bit;
      assume_list->PushBack(info);
    }
  }

  // add assumptions from points within the block.

  for (size_t pind = 0; pind < cfg->GetPointAnnotationCount(); pind++) {
    PointAnnotation pann = cfg->GetPointAnnotation(pind);
    if (end_point && pann.point >= end_point)
      continue;

    BlockCFG *annot_cfg = GetAnnotationCFG(pann.annot);
    if (!annot_cfg) continue;

    Assert(annot_cfg->GetAnnotationKind() != AK_AssertRuntime);

    if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) {
      // get the annotation bit in terms of block entry.
      Bit *point_bit = NULL;
      mcfg->TranslateBit(TRK_Point, pann.point, bit, &point_bit);
      point_bit->MoveRef(&point_bit, assume_list);

      annot_cfg->IncRef(assume_list);

      AssumeInfo info;
      info.annot = annot_cfg;
      info.point = pann.point;
      info.bit = point_bit;
      assume_list->PushBack(info);
    }

    annot_cfg->DecRef();
  }

  // add assumptions from annotation edges within the block, invariants
  // on values accessed by the block, and from the summaries of any callees.

  for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) {
    PEdge *edge = cfg->GetEdge(eind);
    PPoint point = edge->GetSource();

    if (end_point && point >= end_point)
      continue;

    InvariantAssumeVisitor visitor(mcfg, point, assume_list);
    edge->DoVisit(&visitor);

    if (PEdgeAnnotation *nedge = edge->IfAnnotation()) {
      // add an assumption for this annotation.
      BlockCFG *annot_cfg = GetAnnotationCFG(nedge->GetAnnotationId());
      if (!annot_cfg) continue;

      Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg);

      // don't incorporate AssertRuntimes, these are not assumed.
      if (bit && annot_cfg->GetAnnotationKind() != AK_AssertRuntime) {
        // get the annotation bit in terms of block entry.
        Bit *point_bit = NULL;
        mcfg->TranslateBit(TRK_Point, point, bit, &point_bit);
        point_bit->MoveRef(&point_bit, assume_list);

        annot_cfg->IncRef(assume_list);

        AssumeInfo info;
        info.annot = annot_cfg;
        info.point = point;
        info.bit = point_bit;
        assume_list->PushBack(info);
      }

      annot_cfg->DecRef();
    }

    if (BlockId *callee = edge->GetDirectCallee()) {
      GetCallAssumedBits(mcfg, edge, callee, false, assume_list);
      callee->DecRef();
    }
    else if (edge->IsCall()) {
      // add conditional assumes for the indirect targets of the call.
      // this is most useful for baked information and annotations, where
      // we sometimes need to attach information at indirect calls.

      CallEdgeSet *callees = CalleeCache.Lookup(id->BaseVar());
      size_t old_count = assume_list->Size();

      if (callees) {
        for (size_t cind = 0; cind < callees->GetEdgeCount(); cind++) {
          const CallEdge &cedge = callees->GetEdge(cind);
          if (cedge.where.id == id && cedge.where.point == point) {
            cedge.callee->IncRef();
            BlockId *callee = BlockId::Make(B_Function, cedge.callee);

            GetCallAssumedBits(mcfg, edge, callee, true, assume_list);
            callee->DecRef();
          }
        }
      }

      if (assume_list->Size() != old_count) {
        // we managed to do something at this indirect call site.
        // add another assumption restricting the possible callees to
        // only those identified by our callgraph.

        GuardExpVector receiver_list;
        mcfg->TranslateReceiver(point, &receiver_list);

        for (size_t rind = 0; rind < receiver_list.Size(); rind++) {
          const GuardExp &gs = receiver_list[rind];
          gs.guard->IncRef();

          // make a bit: !when || rcv == callee0 || rcv == callee1 || ...
          Bit *extra_bit = Bit::MakeNot(gs.guard);

          for (size_t cind = 0; cind < callees->GetEdgeCount(); cind++) {
            const CallEdge &cedge = callees->GetEdge(cind);
            if (cedge.where.id == id && cedge.where.point == point) {
              Variable *callee_var = cedge.callee;
              callee_var->IncRef();
              Exp *callee_exp = Exp::MakeVar(callee_var);

              gs.exp->IncRef();
              Bit *equal = Exp::MakeCompareBit(B_Equal, callee_exp, gs.exp);

              extra_bit = Bit::MakeOr(extra_bit, equal);
            }
          }

          extra_bit->MoveRef(NULL, assume_list);

          AssumeInfo info;
          info.bit = extra_bit;
          assume_list->PushBack(info);
        }
      }

      CalleeCache.Release(id->BaseVar());
    }
  }

  BodyAnnotCache.Release(id->Function());

  // add assumptions from heap invariants describing values mentioned
  // in added assumptions. we could keep doing this transitively but don't,
  // to ensure termination.
  size_t count = assume_list->Size();
  for (size_t ind = 0; ind < count; ind++) {
    InvariantAssumeVisitor visitor(NULL, 0, assume_list);
    assume_list->At(ind).bit->DoVisit(&visitor);
  }

  CombineAssumeList(assume_list);
}
Ejemplo n.º 2
0
void SplitLoops(BlockCFG *base_cfg, Vector<BlockCFG*> *result_cfg_list)
{
    // get the CFG which will eventually become the loop-free outer function CFG.
    BlockCFG *func_cfg;
    if (base_cfg->GetId()->Kind() == B_FunctionWhole) {
        // make an ID for the outer function body.
        Variable *function_info = base_cfg->GetId()->BaseVar();
        function_info->IncRef();
        BlockId *outer_id = BlockId::Make(B_Function, function_info);

        // make the function CFG by cloning the base CFG with the new ID.
        func_cfg = BlockCFG::Make(outer_id);
        CopyCFGLocationsVariables(base_cfg, func_cfg);
        CopyCFGPointsEdges(base_cfg, func_cfg);
    }
    else if (base_cfg->GetId()->Kind() == B_Function) {
        // this call came from a recursive invocation of SplitLoops after we
        // removed an irreducible loop from the function.
        func_cfg = base_cfg;
    }
    else {
        // just destructively update the original CFG.
        base_cfg->IncRef();
        func_cfg = base_cfg;
    }

    // add a new entry point with a skip edge to the original entry point.
    // loop splitting breaks if the entry point is marked as a loop head.

    PPoint entry = func_cfg->GetEntryPoint();
    Location *loc = func_cfg->GetPointLocation(entry);
    loc->IncRef();
    PPoint new_entry = func_cfg->AddPoint(loc);

    PEdge *skip_edge = PEdge::MakeSkip(new_entry, entry);
    func_cfg->AddEdge(skip_edge);
    func_cfg->SetEntryPoint(new_entry);

    // setup the tables we need to do loop splitting.
    SetupTables();

    // compute the points reachable from the entry point.
    GetEntryReachable(func_cfg);

    // the real loops in the program with back edges.
    Vector<PPoint> loops;

    for (size_t lind = 0; lind < func_cfg->GetLoopHeadCount(); lind++) {
        PPoint head = func_cfg->GetLoopHead(lind).point;
        if (GetLoopBackedges(func_cfg, head))
            loops.PushBack(head);
    }

    // compute reachability and check for irreducible loops.
    for (size_t lind = 0; lind < func_cfg->GetLoopHeadCount(); lind++) {
        const LoopHead &head = func_cfg->GetLoopHead(lind);

        if (GetLoopReachable(func_cfg, head.point)) {
            // loop is irreducible.

            // get the loop's irreducible edges.
            Vector<PEdge*> irreducible_edges;
            GetLoopBody(func_cfg, head.point, &irreducible_edges);
            Assert(!irreducible_edges.Empty());

            // clone the loop's body and remove the irreducible edges.
            ReduceLoop(func_cfg, head.point, irreducible_edges);

            // try again on the modified CFG.
            CleanupTables();
            SplitLoops(func_cfg, result_cfg_list);
            return;
        }
    }

    // there are no irreducible loops at this point so this should
    // never have any entries added.
    Vector<PEdge*> irreducible_edges;

    // compute loop bodies.
    for (size_t lind = 0; lind < loops.Size(); lind++) {
        PPoint head = loops[lind];
        GetLoopBody(func_cfg, head, &irreducible_edges);
        Assert(irreducible_edges.Empty());
    }

    // construct a tree of all the loops. loop A contains loop B
    // if A != B and the head of B is in the body of A.
    PPointListHash loop_tree;

    // split off all the loops in the CFG. make sure we split inner loops
    // before outer, so that the Loop edges on inner loops will appear in
    // the split body for outer loops.
    while (!loops.Empty()) {

        // find a candidate loop to split. this is one whose loop children
        // have already been split off and are no longer in the loops list.
        PPoint loophead = 0;
        for (size_t lind = 0; lind < loops.Size(); lind++) {

            bool is_viable = true;
            for (size_t xlind = 0; xlind < loops.Size(); xlind++) {
                if (xlind == lind)
                    continue;
                Assert(loops[lind] != loops[xlind]);

                if (body_table->Lookup(PPointPair(loops[lind], loops[xlind]))) {
                    is_viable = false;
                    break;
                }
            }

            if (is_viable) {
                loophead = loops[lind];
                loops[lind] = loops.Back();
                loops.PopBack();
                break;
            }
        }

        Assert(loophead);
        BlockCFG *loop_cfg = SplitSingleLoop(loophead, loops, func_cfg);
        result_cfg_list->PushBack(loop_cfg);
    }

    // clear out the loopheads, we don't want them around anymore.
    func_cfg->ClearLoopHeads();

    // trim unreachable points in the function CFG (i.e. bodies of loops that
    // now redirect to point zero), collapse skips and topo sort.
    TrimUnreachable(func_cfg, true);
    TopoSortCFG(func_cfg);

    result_cfg_list->PushBack(func_cfg);
    CleanupTables();

    // fill in any loop parents for the inner loop CFGs, and make sure the
    // result CFGs are ordered correctly, with inner loops before outer loops
    // and the outer function.
    for (size_t cind = 0; cind < result_cfg_list->Size(); cind++) {
        BlockCFG *cfg = result_cfg_list->At(cind);

        for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) {
            if (PEdgeLoop *edge = cfg->GetEdge(eind)->IfLoop()) {
                BlockId *target_id = edge->GetLoopId();

                bool found_target = false;
                for (size_t xcind = 0; xcind < cind; xcind++) {
                    BlockCFG *xcfg = result_cfg_list->At(xcind);
                    if (xcfg->GetId() == target_id) {
                        found_target = true;

                        cfg->GetId()->IncRef();
                        BlockPPoint where(cfg->GetId(), edge->GetSource());
                        xcfg->AddLoopParent(where);

                        // mark the isomorphic points in the parent CFG.
                        GetLoopIsomorphicPoints(cfg, edge, xcfg);

                        break;
                    }
                }

                Assert(found_target);
            }
        }
    }

    // assign the final names to the various loop CFGs.
    FillLoopNames(func_cfg, "loop", *result_cfg_list);
}
Ejemplo n.º 3
0
// mark the trivial/redundant assertions in the specified list.
void MarkRedundantAssertions(BlockMemory *mcfg, Vector<AssertInfo> &asserts)
{
  BlockCFG *cfg = mcfg->GetCFG();

  // assertions are marked redundant in two passes:
  // 1. for each path reaching the assertion, the validity of the assertion is
  //    implied by one or more prior or future assertions.
  //    this pass also picks up assertions which trivially hold, where the
  //    assertion is valid due to the conditions along the paths themselves.
  // 2. there is an isomorphic assertion within an inner loop. it is
  //    sufficient to check just the inner assertion.

  // implication works differently for invariants vs. other assertions,
  // since the invariant condition will be asserted at block exit.

  // for regular assertions, an bit is redundant if (guard ==> bit)
  // is implied by the (oguard ==> obit) for other assertions:

  // VALID((oguard ==> obit) ==> (guard ==> bit))
  // !SAT(!((oguard ==> obit) ==> (guard ==> bit)))
  // !SAT(!(!(oguard ==> obit) || (guard ==> bit)))
  // !SAT((oguard ==> obit) && !(guard ==> bit))
  // !SAT((oguard ==> obit) && !(!guard || bit))
  // !SAT((oguard ==> obit) && guard && !bit)

  // for invariants, a bit is redundant if guard implies the oguard
  // for other invariants with the same asserted bit:

  // VALID(guard ==> oguard)
  // !SAT(!(guard ==> oguard))
  // !SAT(!(!guard || oguard))
  // !SAT(guard && !oguard)

  Solver *solver = new Solver("redundant");

  for (size_t ind = 0; ind < asserts.Size(); ind++) {
    AssertInfo &info = asserts[ind];
    solver->PushContext();

    Assert(info.cls == ASC_Check);

    // assert guard.
    Bit *guard = mcfg->GetGuard(info.point);
    solver->AddAssert(0, guard);

    if (info.kind != ASK_Invariant) {
      // assert !bit.
      Bit *not_bit = Bit::MakeNot(info.bit);

      Bit *result_not_bit;
      mcfg->TranslateBit(TRK_Point, info.point, not_bit, &result_not_bit);
      solver->AddAssert(0, result_not_bit);
    }

    if (!solver->IsSatisfiable()) {
      // the assert is tautological or is proved by the guard, thus trivial.
      info.cls = ASC_Trivial;
      solver->PopContext();
      continue;
    }

    // assert the remaining assertions in the summary hold.
    for (size_t aind = 0; aind < asserts.Size(); aind++) {
      const AssertInfo &oinfo = asserts[aind];

      // skip this assertion itself.
      if (info.point == oinfo.point && info.bit == oinfo.bit)
        continue;

      // skip assertions already marked as trivial or redundant.
      if (oinfo.cls != ASC_Check)
        continue;

      // skip assertions for a different kind than the original.
      // this avoids interference between the different kinds of assertions,
      // though it is unlikely to affect whether we actually mark an
      // assert as redundant.
      if (oinfo.kind != info.kind)
        continue;

      Bit *oguard = mcfg->GetGuard(oinfo.point);

      if (info.kind == ASK_Invariant) {
        // only compare with other invariants for the same bit.
        if (oinfo.bit != info.bit)
          continue;

        // assert !oguard
        Bit *not_oguard = Bit::MakeNot(oguard);
        solver->AddAssert(0, not_oguard);
      }
      else {
        // assert (oguard ==> obit).
        Bit *result_obit;
        mcfg->TranslateBit(TRK_Point, oinfo.point, oinfo.bit, &result_obit);

        Bit *imply_bit = Bit::MakeImply(oguard, result_obit);
        solver->AddAssert(0, imply_bit);
      }
    }

    if (!solver->IsSatisfiable()) {
      // the assert is implied by the remaining assertions, thus redundant.
      info.cls = ASC_Redundant;
    }

    solver->PopContext();
  }

  solver->Clear();
  delete solver;

  for (size_t ind = 0; ind < cfg->GetEdgeCount(); ind++) {
    PEdgeLoop *loop_edge = cfg->GetEdge(ind)->IfLoop();
    if (!loop_edge)
      continue;

    for (size_t aind = 0; aind < asserts.Size(); aind++) {
      AssertInfo &info = asserts[aind];

      if (info.cls != ASC_Check)
        continue;

      if (cfg->IsLoopIsomorphic(info.point)) {
        // this assertion's point is isomorphic to a point within the
        // loop body, so there will be an equivalent loop assertion.
        info.cls = ASC_Redundant;
      }
    }
  }
}
Ejemplo n.º 4
0
void InferSummaries(const Vector<BlockSummary*> &summary_list)
{
  static BaseTimer infer_timer("infer_summaries");
  Timer _timer(&infer_timer);

  if (summary_list.Empty())
    return;

  Variable *function = summary_list[0]->GetId()->BaseVar();
  Vector<BlockCFG*> *annot_list = BodyAnnotCache.Lookup(function->GetName());

  // all traces which might refer to the result of pointer arithmetic.
  Vector<Exp*> arithmetic_list;
  ArithmeticEscape escape(function, arithmetic_list);

  // initial pass over the CFGs to get traces used in pointer arithmetic.
  for (size_t ind = 0; ind < summary_list.Size(); ind++) {
    BlockSummary *sum = summary_list[ind];

    BlockCFG *cfg = sum->GetMemory()->GetCFG();
    for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) {
      PEdge *edge = cfg->GetEdge(eind);

      if (PEdgeAssign *assign_edge = edge->IfAssign()) {
        Exp *left = assign_edge->GetLeftSide();
        Exp *right = assign_edge->GetRightSide();
        ProcessArithmeticAssign(&escape, cfg->GetId(), left, right);
      }
    }
  }

  for (size_t ind = 0; ind < summary_list.Size(); ind++) {
    BlockSummary *sum = summary_list[ind];
    BlockMemory *mcfg = sum->GetMemory();
    BlockCFG *cfg = mcfg->GetCFG();

    // accumulate all the assertions at points in the CFG.
    Vector<AssertInfo> asserts;

    // add assertions at function exit for any postconditions.
    if (cfg->GetId()->Kind() == B_Function) {
      for (size_t aind = 0; annot_list && aind < annot_list->Size(); aind++) {
        BlockCFG *annot_cfg = annot_list->At(aind);

        if (annot_cfg->GetAnnotationKind() != AK_Postcondition)
          continue;
        if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) {
          AssertInfo info;
          info.kind = ASK_Annotation;
          info.cls = ASC_Check;
          info.point = cfg->GetExitPoint();
          info.bit = bit;
          asserts.PushBack(info);
        }
      }
    }

    // add assertions for any point annotations within the CFG.
    for (size_t pind = 0; pind < cfg->GetPointAnnotationCount(); pind++) {
      PointAnnotation pann = cfg->GetPointAnnotation(pind);
      BlockCFG *annot_cfg = GetAnnotationCFG(pann.annot);
      if (!annot_cfg) continue;

      if (annot_cfg->GetAnnotationKind() != AK_Assert)
        continue;

      if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) {
        AssertInfo info;
        info.kind = ASK_Annotation;
        info.cls = ASC_Check;
        info.point = pann.point;
        info.bit = bit;
        asserts.PushBack(info);
      }
    }

    for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) {
      PEdge *edge = cfg->GetEdge(eind);
      PPoint point = edge->GetSource();

      if (PEdgeAnnotation *nedge = edge->IfAnnotation()) {
        // add an assertion for this annotation if it not an assume.
        BlockCFG *annot_cfg = GetAnnotationCFG(nedge->GetAnnotationId());
        if (!annot_cfg) continue;

        if (annot_cfg->GetAnnotationKind() != AK_Assert &&
            annot_cfg->GetAnnotationKind() != AK_AssertRuntime) {
          continue;
        }

        if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) {
          AssertInfo info;
          info.kind = (annot_cfg->GetAnnotationKind() == AK_Assert)
            ? ASK_Annotation : ASK_AnnotationRuntime;
          info.cls = ASC_Check;
          info.point = point;
          info.bit = bit;
          asserts.PushBack(info);
        }
      }

      // add assertions for any invariants affected by a write.

      Exp *left = NULL;
      if (PEdgeAssign *nedge = edge->IfAssign())
        left = nedge->GetLeftSide();
      if (PEdgeCall *nedge = edge->IfCall())
        left = nedge->GetReturnValue();

      // for now our detection of affected invariants is pretty crude;
      // writes to fields can affect type invariants on the field's type
      // which use that field, and writes to global variables can affect
      // invariants on that global. TODO: pin this down once we draw a
      // precise line between which invariants can and can't be checked.

      if (left && left->IsFld()) {
        ExpFld *nleft = left->AsFld();
        String *csu_name = nleft->GetField()->GetCSUType()->GetCSUName();
        Vector<BlockCFG*> *comp_annot_list = CompAnnotCache.Lookup(csu_name);

        for (size_t aind = 0; comp_annot_list &&
                              aind < comp_annot_list->Size(); aind++) {
          BlockCFG *annot_cfg = comp_annot_list->At(aind);

          if (annot_cfg->GetAnnotationKind() != AK_Invariant)
            continue;
          Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg);
          if (!bit) continue;

          Vector<Exp*> lval_list;
          LvalListVisitor visitor(&lval_list);
          bit->DoVisit(&visitor);

          bool uses_field = false;
          for (size_t ind = 0; ind < lval_list.Size(); ind++) {
            if (ExpFld *lval = lval_list[ind]->IfFld()) {
              if (lval->GetField() == nleft->GetField())
                uses_field = true;
            }
          }

          if (uses_field) {
            // this is a type invariant which uses the field being written
            // as an lvalue. we need to assert this write preserves
            // the invariant.
            BlockId *id = annot_cfg->GetId();
            Variable *this_var = Variable::Make(id, VK_This, NULL, 0, NULL);
            Exp *this_exp = Exp::MakeVar(this_var);
            Exp *this_drf = Exp::MakeDrf(this_exp);

            Bit *new_bit = BitReplaceExp(bit, this_drf, nleft->GetTarget());

            AssertInfo info;
            info.kind = ASK_Invariant;
            info.cls = ASC_Check;
            info.point = point;
            info.bit = new_bit;
            asserts.PushBack(info);
          }
        }

        CompAnnotCache.Release(csu_name);
      }

      if (left && left->IsVar()) {
        Variable *var = left->AsVar()->GetVariable();
        if (var->Kind() == VK_Glob) {
          Vector<BlockCFG*> *glob_annot_list =
            InitAnnotCache.Lookup(var->GetName());

          for (size_t aind = 0; glob_annot_list &&
                                aind < glob_annot_list->Size(); aind++) {
            BlockCFG *annot_cfg = glob_annot_list->At(aind);

            Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg);
            if (!bit) continue;

            AssertInfo info;
            info.kind = ASK_Invariant;
            info.cls = ASC_Check;
            info.point = point;
            info.bit = bit;
            asserts.PushBack(info);
          }

          InitAnnotCache.Release(var->GetName());
        }
      }

      if (PEdgeCall *nedge = edge->IfCall()) {
        // add assertions for any callee preconditions.

        // pull preconditions from both direct and indirect calls.
        Vector<Variable*> callee_names;

        if (Variable *callee = nedge->GetDirectFunction()) {
          callee_names.PushBack(callee);
        }
        else {
          CallEdgeSet *callees = CalleeCache.Lookup(function);

          if (callees) {
            for (size_t cind = 0; cind < callees->GetEdgeCount(); cind++) {
              const CallEdge &edge = callees->GetEdge(cind);
              if (edge.where.id == cfg->GetId() && edge.where.point == point)
                callee_names.PushBack(edge.callee);
            }
          }

          // CalleeCache release is below.
        }

        for (size_t cind = 0; cind < callee_names.Size(); cind++) {
          String *callee = callee_names[cind]->GetName();
          Vector<BlockCFG*> *call_annot_list = BodyAnnotCache.Lookup(callee);

          for (size_t aind = 0;
               call_annot_list && aind < call_annot_list->Size(); aind++) {
            BlockCFG *annot_cfg = call_annot_list->At(aind);

            if (annot_cfg->GetAnnotationKind() != AK_Precondition)
              continue;
            if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) {
              ConvertCallsiteMapper mapper(cfg, point, false);
              Bit *caller_bit = bit->DoMap(&mapper);
              if (!caller_bit)
                continue;

              AssertInfo info;
              info.kind = ASK_Annotation;
              info.cls = ASC_Check;
              info.point = point;
              info.bit = caller_bit;
              asserts.PushBack(info);
            }
          }

          BodyAnnotCache.Release(callee);
        }

        if (!nedge->GetDirectFunction())
          CalleeCache.Release(function);
      }

      BufferScanVisitor write_visitor(asserts, arithmetic_list, point, true);
      BufferScanVisitor read_visitor(asserts, arithmetic_list, point, false);
      IntegerScanVisitor integer_visitor(asserts, point);
      GCScanVisitor gcsafe_visitor(asserts, point);

      // only look at the written lvalues for the write visitor.
      if (PEdgeAssign *assign = edge->IfAssign())
        write_visitor.Visit(assign->GetLeftSide());
      if (PEdgeCall *call = edge->IfCall()) {
        if (Exp *returned = call->GetReturnValue())
          write_visitor.Visit(returned);
      }

      edge->DoVisit(&read_visitor);

      // disable integer overflow visitor for now.
      // edge->DoVisit(&integer_visitor);

      edge->DoVisit(&gcsafe_visitor);
    }

    if (cfg->GetId()->Kind() == B_Function) {
      BlockModset *modset = GetBlockModset(cfg->GetId());
      if (modset->CanGC()) {
        AssertInfo info;
        info.kind = ASK_CanGC;
        info.cls = ASC_Check;
        info.point = cfg->GetExitPoint();

        String *name = cfg->GetId()->BaseVar()->GetName();
        Variable *var = Variable::Make(NULL, VK_Glob, name, 0, name);
        Exp *varexp = Exp::MakeVar(var);
        Exp *gcsafe = Exp::MakeGCSafe(varexp, false);
        info.bit = Bit::MakeVar(gcsafe);
        asserts.PushBack(info);
      }
    }

    MarkRedundantAssertions(mcfg, asserts);

    // move the finished assertion list into the summary.
    for (size_t ind = 0; ind < asserts.Size(); ind++) {
      const AssertInfo &info = asserts[ind];
      sum->AddAssert(info.kind, info.cls, info.point, info.bit);
    }
  }

  // infer delta and termination invariants for all summaries.
  for (size_t ind = 0; ind < summary_list.Size(); ind++)
    InferInvariants(summary_list[ind], arithmetic_list);

  BodyAnnotCache.Release(function->GetName());
}
Ejemplo n.º 5
0
void BlockModset::ComputeModset(BlockMemory *mcfg, bool indirect)
{
  static BaseTimer compute_timer("modset_compute");
  Timer _timer(&compute_timer);

  // get any indirect callees for this function, provided they have been
  // computed and stored in the callee database (indirect is set).
  CallEdgeSet *indirect_callees = NULL;
  if (indirect)
    indirect_callees = CalleeCache.Lookup(m_id->BaseVar());

  BlockCFG *cfg = mcfg->GetCFG();
  for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) {
    PEdge *edge = cfg->GetEdge(eind);
    PPoint point = edge->GetSource();

    if (edge->IsAssign() || edge->IsCall()) {
      // process direct assignments along this edge.

      const Vector<GuardAssign>* assigns = mcfg->GetAssigns(point);
      if (assigns) {
        for (size_t aind = 0; aind < assigns->Size(); aind++) {
          const GuardAssign &gasn = assigns->At(aind);
          ProcessUpdatedLval(mcfg, gasn.left, NULL, true, false);

          Exp *use_lval = NULL;
          Exp *kind = mcfg->GetTerminateAssign(point, gasn.left, gasn.right,
                                               &use_lval);
          if (kind) {
            ProcessUpdatedLval(mcfg, use_lval, kind, false, false);
            kind->DecRef();
          }
        }
      }
    }

    // pull in modsets from the direct and indirect callees of the edge.
    if (BlockId *callee = edge->GetDirectCallee()) {
      ComputeModsetCall(mcfg, edge, callee, NULL);
      callee->DecRef();
    }
    else if (edge->IsCall() && indirect_callees) {
      for (size_t ind = 0; ind < indirect_callees->GetEdgeCount(); ind++) {
        const CallEdge &cedge = indirect_callees->GetEdge(ind);

        // when comparing watch out for the case that this is a temporary
        // modset and does not share the same block kind as the edge point.
        if (cedge.where.version == cfg->GetVersion() &&
            cedge.where.point == point &&
            cedge.where.id->Function() == m_id->Function() &&
            cedge.where.id->Loop() == m_id->Loop()) {
          cedge.callee->IncRef();
          BlockId *callee = BlockId::Make(B_Function, cedge.callee);

          ComputeModsetCall(mcfg, edge, callee, cedge.rfld_chain);
          callee->DecRef();
        }
      }
    }
  }

  // sort the modset exps to ensure a consistent representation.
  if (m_modset_list)
    SortVector<PointValue,compare_PointValue>(m_modset_list);
  if (m_assign_list)
    SortVector<GuardAssign,compare_GuardAssign>(m_assign_list);

  if (indirect)
    CalleeCache.Release(m_id->BaseVar());
}