void WherePostcondition::PrintUI(OutStream &out) const { PEdge *edge = m_frame->CFG()->GetSingleOutgoingEdge(m_point); Location *loc = m_frame->CFG()->GetPointLocation(m_point); if (edge->IsLoop()) { const char *loop_name = edge->AsLoop()->GetLoopId()->LoopName(); out << "LoopInvariant [" << loop_name << "]"; } else { out << "Postcondition ["; PEdgeCall *nedge = edge->AsCall(); Exp *function = nedge->GetFunction(); function->PrintUI(out, true); out << ":" << loc->Line() << "]"; } if (m_bit) { Bit *new_bit = BitConvertExitClobber(m_bit); out << " :: "; new_bit->PrintUI(out, true); new_bit->DecRef(); } }
void WherePostcondition::PrintHook(OutStream &out) const { BlockId *id = m_frame->CFG()->GetId(); Variable *func_var = id->BaseVar(); PEdge *edge = m_frame->CFG()->GetSingleOutgoingEdge(m_point); if (edge->IsLoop()) { PEdgeLoop *nedge = edge->AsLoop(); out << nedge->GetLoopId()->Loop()->Value() << " " << func_var->GetName()->Value(); } else { PEdgeCall *nedge = edge->AsCall(); if (Variable *callee = nedge->GetDirectFunction()) { // direct call, just one hook function. out << "post " << callee->GetName()->Value(); } else { // indirect call, one hook function for each callee. CallEdgeSet *callees = CalleeCache.Lookup(func_var); bool found_callee = false; if (callees) { for (size_t eind = 0; eind < callees->GetEdgeCount(); eind++) { const CallEdge &edge = callees->GetEdge(eind); if (edge.where.id == id && edge.where.point == m_point) { if (found_callee) out << "$"; // add the separator found_callee = true; out << "post " << edge.callee->GetName()->Value(); } } } CalleeCache.Release(func_var); } } }
bool CheckFrame(CheckerState *state, CheckerFrame *frame, CheckerPropagate *propagate) { Assert(!state->GetReportKind()); BlockMemory *mcfg = frame->Memory(); BlockCFG *cfg = mcfg->GetCFG(); BlockId *id = cfg->GetId(); if (checker_verbose.IsSpecified()) { logout << "CHECK: " << frame << ": Entering " << id << endl; if (propagate) propagate->Print(); } Where *where = propagate ? propagate->m_where : NULL; // check if we should terminate the search at this point (with or without // generating a report). if (where && where->IsNone()) { WhereNone *nwhere = where->AsNone(); ReportKind kind = nwhere->GetReportKind(); if (kind == RK_None) { if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Ignoring" << endl; return false; } else { if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Propagation failed" << endl; state->SetReport(kind); return true; } } // check for other propagations on the stack with frames for the same block, // and block the recursion if we exceed the checker's depth. we assume that // if we're ever going to terminate in the presence of recursion, we will // do so quickly. if (propagate) { if (uint32_t depth = checker_depth.UIntValue()) { Vector<CheckerFrame*> recurse_frames; for (size_t ind = 0; ind < state->m_stack.Size(); ind++) { CheckerFrame *other_frame = state->m_stack[ind]->m_frame; if (other_frame != frame && other_frame->Memory() == mcfg && !recurse_frames.Contains(other_frame)) recurse_frames.PushBack(other_frame); } if (recurse_frames.Size() >= depth) { state->SetReport(RK_Recursion); return true; } } } // check if we are propagating into some callee. if (where && where->IsPostcondition()) { WherePostcondition *nwhere = where->AsPostcondition(); // expand the callee at the specified point. PPoint point = nwhere->GetPoint(); PEdge *edge = cfg->GetSingleOutgoingEdge(point); if (edge->IsLoop()) { // expanding data from a loop. first try the case that the loop // does not execute at all. if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Trying to skip loop at " << point << endl; state->PushContext(); if (CheckSkipLoop(state, frame, point, nwhere)) return true; state->PopContext(); } if (BlockId *callee = edge->GetDirectCallee()) { // easy case, there is only a single callee. if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Expanding single callee at " << point << ": " << callee << endl; state->PushContext(); if (CheckSingleCallee(state, frame, point, nwhere, callee, true)) return true; state->PopContext(); } else { // iterate through all the possible callees Variable *function = id->BaseVar(); CallEdgeSet *callees = CalleeCache.Lookup(function); Vector<Variable*> callee_vars; if (callees) { for (size_t eind = 0; eind < callees->GetEdgeCount(); eind++) { const CallEdge &edge = callees->GetEdge(eind); if (edge.where.id == id && edge.where.point == point) callee_vars.PushBack(edge.callee); } } SortVector<Variable*,Variable>(&callee_vars); for (size_t cind = 0; cind < callee_vars.Size(); cind++) { Variable *callee = callee_vars[cind]; if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Expanding indirect callee at " << point << ": " << callee << endl; callee->IncRef(); BlockId *callee_id = BlockId::Make(B_Function, callee); state->PushContext(); if (CheckSingleCallee(state, frame, point, nwhere, callee_id, false)) { CalleeCache.Release(function); return true; } state->PopContext(); } if (callee_vars.Empty()) { if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": No callees to expand at " << point << endl; } CalleeCache.Release(function); } return false; } // any precondition we have to propagate up to the callers. WherePrecondition *precondition = NULL; if (where) precondition = where->IfPrecondition(); // whether we will be reconnecting to the caller without any // propagation information. bool reconnect_caller = false; if (precondition) { Bit *bit = precondition->GetBit(); WherePrecondition *dupe_precondition = new WherePrecondition(mcfg, bit); state->m_precondition_list.PushBack(dupe_precondition); } else { // we will propagate to the caller regardless if there is already a caller // hooked up or if we are inside a loop body. if (frame->GetCaller().id != NULL) reconnect_caller = true; if (frame->Kind() == B_Loop) reconnect_caller = true; } if (propagate && reconnect_caller) { // check to see if we are delaying any heap propagation. if (where->IsInvariant()) { Assert(state->m_delayed_propagate_heap == NULL); state->m_delayed_propagate_heap = propagate; } } else if (!precondition && !reconnect_caller) { // check to see if we are performing heap propagation. if (state->m_delayed_propagate_heap) { Assert(propagate == NULL); CheckerPropagate *heap_propagate = state->m_delayed_propagate_heap; state->m_delayed_propagate_heap = NULL; WhereInvariant *invariant = heap_propagate->m_where->AsInvariant(); if (CheckHeapWrites(state, frame, heap_propagate->m_frame, invariant)) return true; state->m_delayed_propagate_heap = heap_propagate; return false; } else if (where && where->IsInvariant()) { return CheckHeapWrites(state, frame, frame, where->AsInvariant()); } Assert(propagate); // don't need to expand the callers or anything else. // we can finally terminate propagation with an error report. if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Nothing to expand, finishing" << endl; state->SetReport(RK_Finished); return true; } if (frame->GetCaller().id != NULL) { // just propagate to the existing caller. if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Returning to caller" << endl; state->PushContext(); if (CheckSingleCaller(state, frame, precondition, frame->GetCaller())) return true; state->PopContext(); } else if (id->Kind() == B_Function) { // propagate to all callers to the function. Variable *function = id->BaseVar(); CallEdgeSet *callers = CallerCache.Lookup(function); Vector<BlockPPoint> caller_points; for (size_t eind = 0; callers && eind < callers->GetEdgeCount(); eind++) { const CallEdge &edge = callers->GetEdge(eind); Assert(edge.callee == function); caller_points.PushBack(edge.where); } SortVector<BlockPPoint,BlockPPoint>(&caller_points); for (size_t cind = 0; cind < caller_points.Size(); cind++) { BlockPPoint caller = caller_points[cind]; if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Checking caller: " << caller << endl; state->PushContext(); if (CheckSingleCaller(state, frame, precondition, caller)) { CallerCache.Release(function); return true; } state->PopContext(); } if (caller_points.Empty()) { if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": No callers to expand" << endl; } CallerCache.Release(function); } else if (id->Kind() == B_Loop) { // check all possible callers of the loop. unroll an iteration before // checking the parents so that if we can't figure out a sufficient // condition for the loop we will stop exploration quickly. // unroll another iteration of the loop. if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Unrolling loop iteration" << endl; state->PushContext(); BlockPPoint recursive_caller(id, cfg->GetExitPoint()); if (CheckSingleCaller(state, frame, precondition, recursive_caller)) return true; state->PopContext(); // check the parents which can initially invoke this loop. if (frame->GetLoopParent().id != NULL) { if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Checking existing loop parent: " << frame->GetLoopParent() << endl; state->PushContext(); if (CheckSingleCaller(state, frame, precondition, frame->GetLoopParent())) return true; state->PopContext(); } else { for (size_t pind = 0; pind < cfg->GetLoopParentCount(); pind++) { BlockPPoint where = cfg->GetLoopParent(pind); if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Checking loop parent: " << where << endl; state->PushContext(); if (CheckSingleCaller(state, frame, precondition, where)) return true; state->PopContext(); } } } else if (id->Kind() == B_Initializer) { // initializers don't have callers, can just ignore this. // TODO: should address why this code is being reached in the first place. if (checker_verbose.IsSpecified()) logout << "CHECK: " << frame << ": Initializer has no callers" << endl; return false; } else { // unknown type of block. Assert(false); } // if we set the state's delayed heap propagation then unset it. if (propagate && state->m_delayed_propagate_heap == propagate) state->m_delayed_propagate_heap = NULL; return false; }