Ejemplo n.º 1
0
// check a single caller to the specified frame at site 'where'.
// return value is whether an error path was found.
bool CheckSingleCaller(CheckerState *state, CheckerFrame *frame,
                       WherePrecondition *precondition, BlockPPoint where)
{
  CheckerFrame *caller_frame = frame->GetCallerFrame();
  CheckerFrame *loop_parent_frame = frame->GetLoopParentFrame();

  bool has_caller = (caller_frame != NULL);
  bool has_loop_parent = (loop_parent_frame != NULL);

  // whether we should keep the caller and callee frames disconnected
  // (unless they already are connected). this is done during loop propagation
  // if there is either a sufficient condition on the propagation or
  // no propagation at all (connecting frames for heap propagation),
  // ensuring we do not have to unroll the loop ad infinitum.
  bool keep_disconnected = false;

  if (frame->Kind() == B_Loop) {
    if (!precondition || precondition->IsIgnoreUnroll())
      keep_disconnected = true;
  }

  // special handling for loop unroll cases.
  if (frame->Kind() == B_Loop && frame->Memory()->GetId() == where.id) {

    // filter out unrolled loop iterations if the caller is disconnected.
    if (keep_disconnected) {
      if (checker_verbose.IsSpecified())
        logout << "CHECK: " << frame << ": Skipping loop unroll" << endl;
      return false;
    }
  }

  // whether we had to create the caller frame.
  bool created_frame = false;

  // whether we need to connect this frame to the caller frame.
  bool connect_frame = false;

  if (has_caller) {
    // we should already have ensured this is a compatible caller.
    Assert(frame->GetCaller() == where);
    Assert(caller_frame);
  }
  else if (where == frame->GetLoopParent()) {
    // connecting to the loop parent of this frame.
    caller_frame = loop_parent_frame;
    Assert(caller_frame);

    connect_frame = true;
  }
  else {
    // no caller to connect to, we will have to make one.
    caller_frame = state->MakeFrame(where.id);

    if (caller_frame == NULL) {
      logout << "WARNING: Missing memory: '" << where.id << "'" << endl;
      return false;
    }

    BlockCFG *cfg = caller_frame->CFG();

    // check for call sites at loop isomorphic points. we will also see the
    // corresponding call site within the loop body, and handling that site
    // will also cover this one.
    if (cfg->IsLoopIsomorphic(where.point)) {
      if (checker_verbose.IsSpecified())
        logout << "CHECK: " << frame << ": Caller is loop isomorphic" << endl;
      state->DeleteFrame(caller_frame);
      return false;
    }

    // for incremental analysis, make sure the call edge uses the current
    // version of the caller CFG. if there is a version mismatch then this
    // call site is for an older version of the CFG; if the current version
    // of the CFG still calls the function then there will be a separate
    // call edge for the updated call site.
    if (cfg->GetVersion() != where.version) {
      if (checker_verbose.IsSpecified())
        logout << "CHECK: " << frame << ": Caller is an older version" << endl;
      state->DeleteFrame(caller_frame);
      return false;
    }

    caller_frame->AssertPointGuard(where.point, true);

    // check for a recursive function/loop call. if there is an existing
    // propagate for this function then just assert its safe/sufficient
    // bit within this caller_frame. TODO: this is unsound as we are not
    // accounting for the *other* parameters to the function which might
    // differ along the recursive calls.
    if (precondition && frame->Memory() == caller_frame->Memory()) {
      Bit *entry_bit = precondition->GetBit();
      caller_frame->AddAssert(entry_bit);
    }

    connect_frame = true;
    created_frame = true;
  }

  // if we are skipping from a loop iteration to the parent, make sure there
  // is a loop child relationship between the two.
  if (keep_disconnected) {
    Assert(frame->Kind() == B_Loop);
    Assert(caller_frame->Memory() != frame->Memory());

    // connect the caller frame as the loop parent if there isn't already one.
    if (loop_parent_frame) {
      Assert(loop_parent_frame == caller_frame);
    }
    else {
      caller_frame->ConnectLoopChild(frame, where.point);
    }
  }

  if (keep_disconnected)
    connect_frame = false;

  if (connect_frame) {
    caller_frame->ConnectCallee(frame, where.point, true);
    frame->PushCallerLoopParent(caller_frame);
  }

  // add any equalities we can between the frame and its caller.
  frame->ExpandPendingExps();

  if (precondition) {
    // get the safe bits for the caller frame.
    Bit *caller_base_bit;
    GuardBitVector caller_safe_list;
    precondition->GetCallerBits(caller_frame, where.point,
                                &caller_base_bit, &caller_safe_list);

    if (CheckFrameList(state, caller_frame, where.point, false, false,
                       caller_base_bit, caller_safe_list)) {
      caller_base_bit->DecRef();
      return true;
    }

    caller_base_bit->DecRef();
  }
  else {
    // continue the checker without any active propagation.
    if (CheckFrameSingle(state, caller_frame, where.point))
      return true;
  }

  if (!has_caller && frame->GetCaller().id != NULL)
    caller_frame->DisconnectCallee(frame, where.point);

  if (!has_loop_parent && frame->GetLoopParent().id != NULL)
    caller_frame->DisconnectLoopChild(frame, where.point);

  if (created_frame)
    state->DeleteFrame(caller_frame);

  return false;
}
Ejemplo n.º 2
0
void GetMatchingHeapWrites(const EscapeAccess &heap_write,
                           Vector<HeapWriteInfo> *writes)
{
  BlockId *id = heap_write.where.id;
  BlockMemory *mcfg = GetBlockMemory(id);

  if (mcfg == NULL) {
    logout << "WARNING: Missing memory: '" << id << "'" << endl;
    return;
  }

  BlockCFG *cfg = mcfg->GetCFG();

  // for incremental analysis, make sure the write CFG uses the right version.
  // as for checking callers, if the CFG has changed but the new one still
  // has a matching write, we will see an escape access for the new CFG.
  if (cfg->GetVersion() != heap_write.where.version) {
    if (checker_verbose.IsSpecified())
      logout << "CHECK: Write is an older version: "
             << heap_write.where.id << ": "
             << heap_write.where.version << endl;
    mcfg->DecRef();
    return;
  }

  PPoint point = heap_write.where.point;
  PPoint exit_point = mcfg->GetCFG()->GetExitPoint();

  // find a point-relative lvalue written at the write point with
  // the sanitized representation from the heap_write trace.
  // TODO: we only match against direct assignments in the CFG for now,
  // ignoring structural copies (which are simple recursive writes).

  PEdge *edge = cfg->GetSingleOutgoingEdge(point);
  Exp *point_lval = NULL;

  if (PEdgeAssign *nedge = edge->IfAssign())
    point_lval = nedge->GetLeftSide();
  else if (PEdgeCall *nedge = edge->IfCall())
    point_lval = nedge->GetReturnValue();

  bool lval_matches = false;

  if (point_lval) {
    if (Exp *new_point_lval = Trace::SanitizeExp(point_lval)) {
      lval_matches = (new_point_lval == heap_write.target->GetValue());
      new_point_lval->DecRef();
    }
  }

  if (!lval_matches) {
    mcfg->DecRef();
    return;
  }

  // it would be nice to remove Val() expressions from this list, but we can't
  // do that as lvalues in memory assignments can contain Val and we want to
  // see the effects of those assignments. TODO: fix.
  GuardExpVector lval_res;
  mcfg->TranslateExp(TRK_Point, point, point_lval, &lval_res);

  for (size_t ind = 0; ind < lval_res.Size(); ind++) {
    const GuardExp &lv = lval_res[ind];

    HeapWriteInfo info;
    info.mcfg = mcfg;
    info.lval = lv.exp;
    info.base_lval = point_lval;

    // look for a condition where the lvalue is not written.
    GuardExpVector exit_vals;
    info.mcfg->GetValComplete(info.lval, NULL, exit_point, &exit_vals);

    for (size_t ind = 0; ind < exit_vals.Size(); ind++) {
      const GuardExp &val = exit_vals[ind];

      // exclude cases where the lvalue refers to its value at block entry.
      if (ExpDrf *nval = val.exp->IfDrf()) {
        if (nval->GetTarget() == info.lval)
          info.exclude.PushBack(val.guard);
      }
    }

    if (!writes->Contains(info)) {
      info.mcfg->IncRef(writes);
      info.lval->IncRef(writes);
      info.base_lval->IncRef(writes);
      IncRefVector<Bit>(info.exclude, writes);
      writes->PushBack(info);
    }
  }

  mcfg->DecRef();
}
Ejemplo n.º 3
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());
}