Пример #1
0
const GRState *MallocChecker::MallocMemAux(CheckerContext &C,  
                                           const CallExpr *CE,
                                           SVal Size, SVal Init,
                                           const GRState *state) {
  unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
  SValBuilder &svalBuilder = C.getSValBuilder();

  // Set the return value.
  SVal retVal = svalBuilder.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
  state = state->BindExpr(CE, retVal);

  // Fill the region with the initialization value.
  state = state->bindDefault(retVal, Init);

  // Set the region's extent equal to the Size parameter.
  const SymbolicRegion *R = cast<SymbolicRegion>(retVal.getAsRegion());
  DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
  DefinedOrUnknownSVal DefinedSize = cast<DefinedOrUnknownSVal>(Size);
  DefinedOrUnknownSVal extentMatchesSize =
    svalBuilder.evalEQ(state, Extent, DefinedSize);

  state = state->assume(extentMatchesSize, true);
  assert(state);
  
  SymbolRef Sym = retVal.getAsLocSymbol();
  assert(Sym);

  // Set the symbol's state to Allocated.
  return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
}
Пример #2
0
std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
  ProgramPoint P = N->getLocation();
  const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
  assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");

  // FIXME: Use CallEvent to abstract this over all calls.
  const Stmt *CallSite = CExit->getCalleeContext()->getCallSite();
  const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
  if (!CE)
    return "";

  if (!N)
    return getMessageForSymbolNotFound();

  // Check if one of the parameters are set to the interesting symbol.
  ProgramStateRef State = N->getState();
  const LocationContext *LCtx = N->getLocationContext();
  unsigned ArgIndex = 0;
  for (CallExpr::const_arg_iterator I = CE->arg_begin(),
                                    E = CE->arg_end(); I != E; ++I, ++ArgIndex){
    SVal SV = State->getSVal(*I, LCtx);

    // Check if the variable corresponding to the symbol is passed by value.
    SymbolRef AS = SV.getAsLocSymbol();
    if (AS == Sym) {
      return getMessageForArg(*I, ArgIndex);
    }

    // Check if the parameter is a pointer to the symbol.
    if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
      SVal PSV = State->getSVal(Reg->getRegion());
      SymbolRef AS = PSV.getAsLocSymbol();
      if (AS == Sym) {
        return getMessageForArg(*I, ArgIndex);
      }
    }
  }

  // Check if we are returning the interesting symbol.
  SVal SV = State->getSVal(CE, LCtx);
  SymbolRef RetSym = SV.getAsLocSymbol();
  if (RetSym == Sym) {
    return getMessageForReturn(CE);
  }

  return getMessageForSymbolNotFound();
}
Пример #3
0
std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
  if (!N)
    return getMessageForSymbolNotFound();

  ProgramPoint P = N->getLocation();
  CallExitEnd CExit = P.castAs<CallExitEnd>();

  // FIXME: Use CallEvent to abstract this over all calls.
  const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
  const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
  if (!CE)
    return {};

  // Check if one of the parameters are set to the interesting symbol.
  unsigned ArgIndex = 0;
  for (CallExpr::const_arg_iterator I = CE->arg_begin(),
                                    E = CE->arg_end(); I != E; ++I, ++ArgIndex){
    SVal SV = N->getSVal(*I);

    // Check if the variable corresponding to the symbol is passed by value.
    SymbolRef AS = SV.getAsLocSymbol();
    if (AS == Sym) {
      return getMessageForArg(*I, ArgIndex);
    }

    // Check if the parameter is a pointer to the symbol.
    if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
      // Do not attempt to dereference void*.
      if ((*I)->getType()->isVoidPointerType())
        continue;
      SVal PSV = N->getState()->getSVal(Reg->getRegion());
      SymbolRef AS = PSV.getAsLocSymbol();
      if (AS == Sym) {
        return getMessageForArg(*I, ArgIndex);
      }
    }
  }

  // Check if we are returning the interesting symbol.
  SVal SV = N->getSVal(CE);
  SymbolRef RetSym = SV.getAsLocSymbol();
  if (RetSym == Sym) {
    return getMessageForReturn(CE);
  }

  return getMessageForSymbolNotFound();
}
Пример #4
0
bool StoreManager::FindUniqueBinding::HandleBinding(StoreManager& SMgr,
                                                    Store store,
                                                    const MemRegion* R,
                                                    SVal val) {
  SymbolRef SymV = val.getAsLocSymbol();
  if (!SymV || SymV != Sym)
    return true;

  if (Binding) {
    First = false;
    return false;
  }
  else
    Binding = R;

  return true;
}
Пример #5
0
void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
                                   const LocationContext *LC,
                                   const GRState *rootState,
                                   BugReporter& BR) {

  SVal ParamL = rootState->getLValue(Param, LC);
  const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>();
  assert (ParamR && "Parameters always have VarRegions.");
  SVal ParamSVal = rootState->getSVal(ParamR);

  // FIXME: For now assume that ParamSVal is symbolic.  We need to generalize
  // this later.
  SymbolRef ParamSym = ParamSVal.getAsLocSymbol();
  if (!ParamSym)
    return;

  // Iterate over the implicit-null dereferences.
  ExplodedNode *const* I,  *const* E;
  llvm::tie(I, E) = GetImplicitNullDereferences(Eng);
  for ( ; I != E; ++I) {
    const GRState *state = (*I)->getState();
    SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt());
    if (location.getAsSymbol() != ParamSym)
      continue;

    // Emit an error.
    std::string sbuf;
    llvm::raw_string_ostream os(sbuf);
      os << "Potential null dereference.  According to coding standards ";

    if (isNSErrorWarning)
      os << "in 'Creating and Returning NSError Objects' the parameter '";
    else
      os << "documented in CoreFoundation/CFError.h the parameter '";

    os << Param << "' may be null.";

    BugReport *report = new BugReport(*this, os.str(), *I);
    // FIXME: Notable symbols are now part of the report.  We should
    //  add support for notable symbols in BugReport.
    //    BR.addNotableSymbol(SV->getSymbol());
    BR.EmitReport(report);
  }
}
Пример #6
0
void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
                                           CheckerContext &C) const {
  unsigned idx = InvalidIdx;
  ProgramStateRef State = C.getState();

  const FunctionDecl *FD = C.getCalleeDecl(CE);
  if (!FD || FD->getKind() != Decl::Function)
    return;
  
  StringRef funName = C.getCalleeName(FD);
  if (funName.empty())
    return;

  // If it is a call to an allocator function, it could be a double allocation.
  idx = getTrackedFunctionIndex(funName, true);
  if (idx != InvalidIdx) {
    const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
    if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
      if (const AllocationState *AS = State->get<AllocatedData>(V)) {
        if (!definitelyReturnedError(AS->Region, State, C.getSValBuilder())) {
          // Remove the value from the state. The new symbol will be added for
          // tracking when the second allocator is processed in checkPostStmt().
          State = State->remove<AllocatedData>(V);
          ExplodedNode *N = C.addTransition(State);
          if (!N)
            return;
          initBugType();
          SmallString<128> sbuf;
          llvm::raw_svector_ostream os(sbuf);
          unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
          os << "Allocated data should be released before another call to "
              << "the allocator: missing a call to '"
              << FunctionsToTrack[DIdx].Name
              << "'.";
          BugReport *Report = new BugReport(*BT, os.str(), N);
          Report->addVisitor(new SecKeychainBugVisitor(V));
          Report->addRange(ArgExpr->getSourceRange());
          Report->markInteresting(AS->Region);
          C.emitReport(Report);
        }
      }
    return;
  }

  // Is it a call to one of deallocator functions?
  idx = getTrackedFunctionIndex(funName, false);
  if (idx == InvalidIdx)
    return;

  // Check the argument to the deallocator.
  const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
  SVal ArgSVal = State->getSVal(ArgExpr, C.getLocationContext());

  // Undef is reported by another checker.
  if (ArgSVal.isUndef())
    return;

  SymbolRef ArgSM = ArgSVal.getAsLocSymbol();

  // If the argument is coming from the heap, globals, or unknown, do not
  // report it.
  bool RegionArgIsBad = false;
  if (!ArgSM) {
    if (!isBadDeallocationArgument(ArgSVal.getAsRegion()))
      return;
    RegionArgIsBad = true;
  }

  // Is the argument to the call being tracked?
  const AllocationState *AS = State->get<AllocatedData>(ArgSM);
  if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) {
    return;
  }
  // If trying to free data which has not been allocated yet, report as a bug.
  // TODO: We might want a more precise diagnostic for double free
  // (that would involve tracking all the freed symbols in the checker state).
  if (!AS || RegionArgIsBad) {
    // It is possible that this is a false positive - the argument might
    // have entered as an enclosing function parameter.
    if (isEnclosingFunctionParam(ArgExpr))
      return;

    ExplodedNode *N = C.addTransition(State);
    if (!N)
      return;
    initBugType();
    BugReport *Report = new BugReport(*BT,
        "Trying to free data which has not been allocated.", N);
    Report->addRange(ArgExpr->getSourceRange());
    if (AS)
      Report->markInteresting(AS->Region);
    C.emitReport(Report);
    return;
  }

  // Process functions which might deallocate.
  if (FunctionsToTrack[idx].Kind == PossibleAPI) {

    if (funName == "CFStringCreateWithBytesNoCopy") {
      const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts();
      // NULL ~ default deallocator, so warn.
      if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(),
          Expr::NPC_ValueDependentIsNotNull)) {
        const AllocationPair AP = std::make_pair(ArgSM, AS);
        generateDeallocatorMismatchReport(AP, ArgExpr, C);
        return;
      }
      // One of the default allocators, so warn.
      if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) {
        StringRef DeallocatorName = DE->getFoundDecl()->getName();
        if (DeallocatorName == "kCFAllocatorDefault" ||
            DeallocatorName == "kCFAllocatorSystemDefault" ||
            DeallocatorName == "kCFAllocatorMalloc") {
          const AllocationPair AP = std::make_pair(ArgSM, AS);
          generateDeallocatorMismatchReport(AP, ArgExpr, C);
          return;
        }
        // If kCFAllocatorNull, which does not deallocate, we still have to
        // find the deallocator.
        if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
          return;
      }
      // In all other cases, assume the user supplied a correct deallocator
      // that will free memory so stop tracking.
      State = State->remove<AllocatedData>(ArgSM);
      C.addTransition(State);
      return;
    }

    llvm_unreachable("We know of no other possible APIs.");
  }

  // The call is deallocating a value we previously allocated, so remove it
  // from the next state.
  State = State->remove<AllocatedData>(ArgSM);

  // Check if the proper deallocator is used.
  unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
  if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) {
    const AllocationPair AP = std::make_pair(ArgSM, AS);
    generateDeallocatorMismatchReport(AP, ArgExpr, C);
    return;
  }

  // If the buffer can be null and the return status can be an error,
  // report a bad call to free.
  if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
      !definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
    ExplodedNode *N = C.addTransition(State);
    if (!N)
      return;
    initBugType();
    BugReport *Report = new BugReport(*BT,
        "Only call free if a valid (non-NULL) buffer was returned.", N);
    Report->addVisitor(new SecKeychainBugVisitor(ArgSM));
    Report->addRange(ArgExpr->getSourceRange());
    Report->markInteresting(AS->Region);
    C.emitReport(Report);
    return;
  }

  C.addTransition(State);
}
Пример #7
0
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode,
                                        const Stmt *S,
                                        BugReport &report, bool IsArg) {
  if (!S || !ErrorNode)
    return false;

  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
    S = OVE->getSourceExpr();

  const ExplodedNode *N = ErrorNode;

  const Expr *Inner = 0;
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    Ex = Ex->IgnoreParenCasts();
    if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
      Inner = Ex;
  }

  if (IsArg) {
    assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call");
  } else {
    // Walk through nodes until we get one that matches the statement exactly.
    // Alternately, if we hit a known lvalue for the statement, we know we've
    // gone too far (though we can likely track the lvalue better anyway).
    do {
      const ProgramPoint &pp = N->getLocation();
      if (Optional<PostStmt> ps = pp.getAs<PostStmt>()) {
        if (ps->getStmt() == S || ps->getStmt() == Inner)
          break;
      } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) {
        if (CEE->getCalleeContext()->getCallSite() == S ||
            CEE->getCalleeContext()->getCallSite() == Inner)
          break;
      }
      N = N->getFirstPred();
    } while (N);

    if (!N)
      return false;
  }
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) {
    const MemRegion *R = 0;

    // First check if this is a DeclRefExpr for a C++ reference type.
    // For those, we want the location of the reference.
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Inner)) {
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        if (VD->getType()->isReferenceType()) {
          ProgramStateManager &StateMgr = state->getStateManager();
          MemRegionManager &MRMgr = StateMgr.getRegionManager();
          R = MRMgr.getVarRegion(VD, N->getLocationContext());
        }
      }
    }

    // For all other cases, find the location by scouring the ExplodedGraph.
    if (!R) {
      // Find the ExplodedNode where the lvalue (the value of 'Ex')
      // was computed.  We need this for getting the location value.
      const ExplodedNode *LVNode = N;
      while (LVNode) {
        if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
          if (P->getStmt() == Inner)
            break;
        }
        LVNode = LVNode->getFirstPred();
      }
      assert(LVNode && "Unable to find the lvalue node.");
      ProgramStateRef LVState = LVNode->getState();
      R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
    }

    if (R) {
      // Mark both the variable region and its contents as interesting.
      SVal V = state->getRawSVal(loc::MemRegionVal(R));

      // If the value matches the default for the variable region, that
      // might mean that it's been cleared out of the state. Fall back to
      // the full argument expression (with casts and such intact).
      if (IsArg) {
        bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
        if (!UseArgValue) {
          const SymbolRegionValue *SRV =
            dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
          if (SRV)
            UseArgValue = (SRV->getRegion() == R);
        }
        if (UseArgValue)
          V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
      }

      report.markInteresting(R);
      report.markInteresting(V);
      report.addVisitor(new UndefOrNullArgVisitor(R));

      if (isa<SymbolicRegion>(R)) {
        TrackConstraintBRVisitor *VI =
          new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
        report.addVisitor(VI);
      }

      // If the contents are symbolic, find out when they became null.
      if (V.getAsLocSymbol()) {
        BugReporterVisitor *ConstraintTracker =
          new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
        report.addVisitor(ConstraintTracker);

        // Add visitor, which will suppress inline defensive checks.
        if (ErrorNode->getState()->isNull(V).isConstrainedTrue()) {
          BugReporterVisitor *IDCSuppressor =
            new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
                                                     ErrorNode);
          report.addVisitor(IDCSuppressor);
        }
      }

      if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
        report.addVisitor(new FindLastStoreBRVisitor(*KV, R));
      return true;
    }
  }

  // If the expression is not an "lvalue expression", we can still
  // track the constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // If the value came from an inlined function call, we should at least make
  // sure that function isn't pruned in our output.
  if (const Expr *E = dyn_cast<Expr>(S))
    S = E->IgnoreParenCasts();
  ReturnVisitor::addVisitorIfNecessary(N, S, report);

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());
  // Is it a symbolic value?
  if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) {
    // At this point we are dealing with the region's LValue.
    // However, if the rvalue is a symbolic region, we should track it as well.
    SVal RVal = state->getSVal(L->getRegion());
    const MemRegion *RegionRVal = RVal.getAsRegion();
    report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));

    if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
      report.markInteresting(RegionRVal);
      report.addVisitor(new TrackConstraintBRVisitor(
        loc::MemRegionVal(RegionRVal), false));
    }
  }

  return true;
}
Пример #8
0
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
                                        BugReport &report, bool IsArg) {
  if (!S || !N)
    return false;

  if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
    S = OVE->getSourceExpr();

  if (IsArg) {
    assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call");
  } else {
    // Walk through nodes until we get one that matches the statement exactly.
    do {
      const ProgramPoint &pp = N->getLocation();
      if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
        if (ps->getStmt() == S)
          break;
      } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
        if (CEE->getCalleeContext()->getCallSite() == S)
          break;
      }
      N = N->getFirstPred();
    } while (N);

    if (!N)
      return false;
  }
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    // Strip off parens and casts. Note that this will never have issues with
    // C++ user-defined implicit conversions, because those have a constructor
    // or function call inside.
    Ex = Ex->IgnoreParenCasts();
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
      // FIXME: Right now we only track VarDecls because it's non-trivial to
      // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        ProgramStateManager &StateMgr = state->getStateManager();
        MemRegionManager &MRMgr = StateMgr.getRegionManager();
        const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext());

        // Mark both the variable region and its contents as interesting.
        SVal V = state->getRawSVal(loc::MemRegionVal(R));

        // If the value matches the default for the variable region, that
        // might mean that it's been cleared out of the state. Fall back to
        // the full argument expression (with casts and such intact).
        if (IsArg) {
          bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
          if (!UseArgValue) {
            const SymbolRegionValue *SRV =
              dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
            if (SRV)
              UseArgValue = (SRV->getRegion() == R);
          }
          if (UseArgValue)
            V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
        }

        report.markInteresting(R);
        report.markInteresting(V);
        report.addVisitor(new UndefOrNullArgVisitor(R));

        // If the contents are symbolic, find out when they became null.
        if (V.getAsLocSymbol()) {
          BugReporterVisitor *ConstraintTracker
            = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false);
          report.addVisitor(ConstraintTracker);
        }

        report.addVisitor(new FindLastStoreBRVisitor(V, R));
        return true;
      }
    }
  }

  // If the expression does NOT refer to a variable, we can still track
  // constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());

  // Is it a symbolic value?
  if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
    // At this point we are dealing with the region's LValue.
    // However, if the rvalue is a symbolic region, we should track it as well.
    SVal RVal = state->getSVal(L->getRegion());
    const MemRegion *RegionRVal = RVal.getAsRegion();
    report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));


    if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
      report.markInteresting(RegionRVal);
      report.addVisitor(new TrackConstraintBRVisitor(
        loc::MemRegionVal(RegionRVal), false));
    }
  } else {
    // Otherwise, if the value came from an inlined function call,
    // we should at least make sure that function isn't pruned in our output.
    if (const Expr *E = dyn_cast<Expr>(S))
      S = E->IgnoreParenCasts();
    ReturnVisitor::addVisitorIfNecessary(N, S, report);
  }

  return true;
}
void bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
                                        BugReport &report) {
  if (!S || !N)
    return;

  ProgramStateManager &StateMgr = N->getState()->getStateManager();

  // Walk through nodes until we get one that matches the statement exactly.
  while (N) {
    const ProgramPoint &pp = N->getLocation();
    if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
      if (ps->getStmt() == S)
        break;
    } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
      if (CEE->getCalleeContext()->getCallSite() == S)
        break;
    }
    N = N->getFirstPred();
  }

  if (!N)
    return;
  
  ProgramStateRef state = N->getState();

  // See if the expression we're interested refers to a variable. 
  // If so, we can track both its contents and constraints on its value.
  if (const Expr *Ex = dyn_cast<Expr>(S)) {
    // Strip off parens and casts. Note that this will never have issues with
    // C++ user-defined implicit conversions, because those have a constructor
    // or function call inside.
    Ex = Ex->IgnoreParenCasts();
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
      // FIXME: Right now we only track VarDecls because it's non-trivial to
      // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        const VarRegion *R =
          StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());

        // Mark both the variable region and its contents as interesting.
        SVal V = state->getRawSVal(loc::MemRegionVal(R));
        report.markInteresting(R);
        report.markInteresting(V);

        // If the contents are symbolic, find out when they became null.
        if (V.getAsLocSymbol()) {
          BugReporterVisitor *ConstraintTracker
            = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false);
          report.addVisitor(ConstraintTracker);
        }

        report.addVisitor(new FindLastStoreBRVisitor(V, R));
        return;
      }
    }
  }

  // If the expression does NOT refer to a variable, we can still track
  // constraints on its contents.
  SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());

  // Uncomment this to find cases where we aren't properly getting the
  // base value that was dereferenced.
  // assert(!V.isUnknownOrUndef());

  // Is it a symbolic value?
  if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
    const MemRegion *Base = L->getRegion()->getBaseRegion();
    if (isa<SymbolicRegion>(Base)) {
      report.markInteresting(Base);
      report.addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(Base),
                                                      false));
    }
  } else {
    // Otherwise, if the value came from an inlined function call,
    // we should at least make sure that function isn't pruned in our output.
    ReturnVisitor::addVisitorIfNecessary(N, S, report);
  }
}