Пример #1
0
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
                                     SVal lock, bool isTryLock) {
  
  const MemRegion *lockR = lock.getAsRegion();
  if (!lockR)
    return;
  
  const GRState *state = C.getState();
  
  SVal X = state->getSVal(CE);
  if (X.isUnknownOrUndef())
    return;
  
  DefinedSVal retVal = cast<DefinedSVal>(X);
  const GRState *lockSucc = state;
  
  if (isTryLock) {
      // Bifurcate the state, and allow a mode where the lock acquisition fails.
    const GRState *lockFail;
    llvm::tie(lockFail, lockSucc) = state->assume(retVal);    
    assert(lockFail && lockSucc);
    C.addTransition(C.generateNode(CE, lockFail));
  }
  else {
      // Assume that the return value was 0.
    lockSucc = state->assume(retVal, false);
    assert(lockSucc);
  }
  
    // Record that the lock was acquired.  
  lockSucc = lockSucc->add<LockSet>(lockR);
  
  C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
                  C.getPredecessor());
}
Пример #2
0
void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
                                     CheckerContext &C) const
{
  if (!SymReaper.hasDeadSymbols())
    return;

  const GRState *state = C.getState();
  RegionStateTy RS = state->get<RegionState>();
  RegionStateTy::Factory &F = state->get_context<RegionState>();

  for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
    if (SymReaper.isDead(I->first)) {
      if (I->second.isAllocated()) {
        if (ExplodedNode *N = C.generateNode()) {
          if (!BT_Leak)
            BT_Leak.reset(new BuiltinBug("Memory leak",
                    "Allocated memory never released. Potential memory leak."));
          // FIXME: where it is allocated.
          BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
          C.EmitReport(R);
        }
      }

      // Remove the dead symbol from the map.
      RS = F.remove(RS, I->first);
    }
  }
  C.generateNode(state->set<RegionState>(RS));
}
void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
                                               CheckerContext &C) const {
  
  // Get the result type of the call.
  QualType expectedResultTy = CE->getType();

  // Fetch the signature of the called function.
  const GRState *state = C.getState();

  SVal V = state->getSVal(CE);
  
  if (V.isUnknown())
    return;
  
  // Casting to void?  Discard the value.
  if (expectedResultTy->isVoidType()) {
    C.generateNode(state->BindExpr(CE, UnknownVal()));
    return;
  }                   

  const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
  if (!callee)
    return;

  QualType actualResultTy;
  
  if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
    const FunctionDecl *FD = FT->getDecl();
    actualResultTy = FD->getResultType();
  }
  else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
    const BlockTextRegion *BR = BD->getCodeRegion();
    const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>();
    const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
    actualResultTy = FT->getResultType();
  }

  // Can this happen?
  if (actualResultTy.isNull())
    return;

  // For now, ignore references.
  if (actualResultTy->getAs<ReferenceType>())
    return;
  

  // Are they the same?
  if (expectedResultTy != actualResultTy) {
    // FIXME: Do more checking and actual emit an error. At least performing
    // the cast avoids some assertion failures elsewhere.
    SValBuilder &svalBuilder = C.getSValBuilder();
    V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
    C.generateNode(state->BindExpr(CE, V));
  }
}
Пример #4
0
void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
    const GRState *state = C.getState();
    if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
        return;
    // Check the legality of the 'whence' argument of 'fseek'.
    SVal Whence = state->getSVal(CE->getArg(2));
    const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);

    if (!CI)
        return;

    int64_t x = CI->getValue().getSExtValue();
    if (x >= 0 && x <= 2)
        return;

    if (ExplodedNode *N = C.generateNode(state)) {
        if (!BT_illegalwhence)
            BT_illegalwhence.reset(new BuiltinBug("Illegal whence argument",
                                                  "The whence argument to fseek() should be "
                                                  "SEEK_SET, SEEK_END, or SEEK_CUR."));
        BugReport *R = new BugReport(*BT_illegalwhence,
                                     BT_illegalwhence->getDescription(), N);
        C.EmitReport(R);
    }
}
Пример #5
0
void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
                                       CheckerContext &C) const {
  // Using a fixed address is not portable because that address will probably
  // not be valid in all environments or platforms.

  if (B->getOpcode() != BO_Assign)
    return;

  QualType T = B->getType();
  if (!T->isPointerType())
    return;

  const GRState *state = C.getState();

  SVal RV = state->getSVal(B->getRHS());

  if (!RV.isConstant() || RV.isZeroConstant())
    return;

  if (ExplodedNode *N = C.generateNode()) {
    if (!BT)
      BT.reset(new BuiltinBug("Use fixed address", 
                          "Using a fixed address is not portable because that "
                          "address will probably not be valid in all "
                          "environments or platforms."));
    RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
    R->addRange(B->getRHS()->getSourceRange());
    C.EmitReport(R);
  }
}
Пример #6
0
void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
                                         const ObjCAtSynchronizedStmt *S) {

  const Expr *Ex = S->getSynchExpr();
  const GRState *state = C.getState();
  SVal V = state->getSVal(Ex);

  // Uninitialized value used for the mutex?
  if (isa<UndefinedVal>(V)) {
    if (ExplodedNode *N = C.generateSink()) {
      if (!BT_undef)
        BT_undef = new BuiltinBug("Uninitialized value used as mutex "
                                  "for @synchronized");
      EnhancedBugReport *report =
        new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
      C.EmitReport(report);
    }
    return;
  }

  if (V.isUnknown())
    return;

  // Check for null mutexes.
  const GRState *notNullState, *nullState;
  llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));

  if (nullState) {
    if (!notNullState) {
      // Generate an error node.  This isn't a sink since
      // a null mutex just means no synchronization occurs.
      if (ExplodedNode *N = C.generateNode(nullState)) {
        if (!BT_null)
          BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
                                   "(no synchronization will occur)");
        EnhancedBugReport *report =
          new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
        report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
                                  Ex);

        C.EmitReport(report);
        return;
      }
    }
    // Don't add a transition for 'nullState'.  If the value is
    // under-constrained to be null or non-null, assume it is non-null
    // afterwards.
  }

  if (notNullState)
    C.addTransition(notNullState);
}
Пример #7
0
// Check if the location is a freed symbolic region.
void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const {
  SymbolRef Sym = l.getLocSymbolInBase();
  if (Sym) {
    const RefState *RS = C.getState()->get<RegionState>(Sym);
    if (RS && RS->isReleased()) {
      if (ExplodedNode *N = C.generateNode()) {
        if (!BT_UseFree)
          BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory "
                                          "after it is freed."));

        BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
                                     N);
        C.EmitReport(R);
      }
    }
  }
}
Пример #8
0
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
                                     SVal lock) {

  const MemRegion *lockR = lock.getAsRegion();
  if (!lockR)
    return;
  
  const GRState *state = C.getState();

  // Record that the lock was released.  
  // FIXME: Handle unlocking locks that were never acquired.  This may
  // require IPA for wrappers.
  const GRState *unlockState = state->remove<LockSet>(lockR);
  
  if (state == unlockState)
    return;
  
  C.addTransition(C.generateNode(CE, unlockState));  
}
Пример #9
0
void CastToStructChecker::checkPreStmt(const CastExpr *CE,
                                       CheckerContext &C) const {
  const Expr *E = CE->getSubExpr();
  ASTContext &Ctx = C.getASTContext();
  QualType OrigTy = Ctx.getCanonicalType(E->getType());
  QualType ToTy = Ctx.getCanonicalType(CE->getType());

  const PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
  const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());

  if (!ToPTy || !OrigPTy)
    return;

  QualType OrigPointeeTy = OrigPTy->getPointeeType();
  QualType ToPointeeTy = ToPTy->getPointeeType();

  if (!ToPointeeTy->isStructureOrClassType())
    return;

  // We allow cast from void*.
  if (OrigPointeeTy->isVoidType())
    return;

  // Now the cast-to-type is struct pointer, the original type is not void*.
  if (!OrigPointeeTy->isRecordType()) {
    if (ExplodedNode *N = C.generateNode()) {
      if (!BT)
        BT.reset(new BuiltinBug("Cast from non-struct type to struct type",
                            "Casting a non-structure type to a structure type "
                            "and accessing a field can lead to memory access "
                            "errors or data corruption."));
      RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
      R->addRange(CE->getSourceRange());
      C.EmitReport(R);
    }
  }
}
Пример #10
0
void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
                                              ObjCMessage msg) {
  
  if (!BT) {
    BT = new APIMisuse("message incorrectly sent to class instead of class "
                       "instance");
  
    ASTContext &Ctx = C.getASTContext();
    releaseS = GetNullarySelector("release", Ctx);
    retainS = GetNullarySelector("retain", Ctx);
    autoreleaseS = GetNullarySelector("autorelease", Ctx);
    drainS = GetNullarySelector("drain", Ctx);
  }
  
  if (msg.isInstanceMessage())
    return;
  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
  assert(Class);

  Selector S = msg.getSelector();
  if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
    return;
  
  if (ExplodedNode *N = C.generateNode()) {
    llvm::SmallString<200> buf;
    llvm::raw_svector_ostream os(buf);

    os << "The '" << S.getAsString() << "' message should be sent to instances "
          "of class '" << Class->getName()
       << "' and not the class directly";
  
    RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
    report->addRange(msg.getSourceRange());
    C.EmitReport(report);
  }
}
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              const ProgramState *state,
                                              ObjCMessage msg) const {
  ASTContext &Ctx = C.getASTContext();

  // Check the return type of the message expression.  A message to nil will
  // return different values depending on the return type and the architecture.
  QualType RetTy = msg.getType(Ctx);

  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);

  if (CanRetTy->isStructureOrClassType()) {
    // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
    // have the "use of undefined value" be smarter about where the
    // undefined value came from.
    if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){
      if (ExplodedNode *N = C.generateSink(state))
        emitNilReceiverBug(C, msg, N);
      return;
    }

    // The result is not consumed by a surrounding expression.  Just propagate
    // the current state.
    C.addTransition(state);
    return;
  }

  // Other cases: check if the return type is smaller than void*.
  if (CanRetTy != Ctx.VoidTy &&
      C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) {
    // Compute: sizeof(void *) and sizeof(return type)
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);

    if (voidPtrSize < returnTypeSize &&
        !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
          (Ctx.FloatTy == CanRetTy ||
           Ctx.DoubleTy == CanRetTy ||
           Ctx.LongDoubleTy == CanRetTy ||
           Ctx.LongLongTy == CanRetTy ||
           Ctx.UnsignedLongLongTy == CanRetTy))) {
      if (ExplodedNode *N = C.generateSink(state))
        emitNilReceiverBug(C, msg, N);
      return;
    }

    // Handle the safe cases where the return value is 0 if the
    // receiver is nil.
    //
    // FIXME: For now take the conservative approach that we only
    // return null values if we *know* that the receiver is nil.
    // This is because we can have surprises like:
    //
    //   ... = [[NSScreens screens] objectAtIndex:0];
    //
    // What can happen is that [... screens] could return nil, but
    // it most likely isn't nil.  We should assume the semantics
    // of this case unless we have *a lot* more knowledge.
    //
    SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
    C.generateNode(state->BindExpr(msg.getOriginExpr(), V));
    return;
  }

  C.addTransition(state);
}
Пример #12
0
void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
                                             const CallExpr *CE)
{
  const Expr* Callee = CE->getCallee();
  const GRState *state = C.getState();
  SVal CallV = state->getSVal(Callee);
  const FunctionDecl* FD = CallV.getAsFunctionDecl();

  if (!FD)
    return;
  
  ASTContext &Ctx = C.getASTContext();
  if (!II)
    II = &Ctx.Idents.get("CFNumberCreate");

  if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
    return;

  // Get the value of the "theType" argument.
  SVal TheTypeVal = state->getSVal(CE->getArg(1));

  // FIXME: We really should allow ranges of valid theType values, and
  //   bifurcate the state appropriately.
  nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
  if (!V)
    return;

  uint64_t NumberKind = V->getValue().getLimitedValue();
  Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);

  // FIXME: In some cases we can emit an error.
  if (!TargetSize.isKnown())
    return;

  // Look at the value of the integer being passed by reference.  Essentially
  // we want to catch cases where the value passed in is not equal to the
  // size of the type being created.
  SVal TheValueExpr = state->getSVal(CE->getArg(2));

  // FIXME: Eventually we should handle arbitrary locations.  We can do this
  //  by having an enhanced memory model that does low-level typing.
  loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
  if (!LV)
    return;

  const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
  if (!R)
    return;

  QualType T = Ctx.getCanonicalType(R->getValueType());

  // FIXME: If the pointee isn't an integer type, should we flag a warning?
  //  People can do weird stuff with pointers.

  if (!T->isIntegerType())
    return;

  uint64_t SourceSize = Ctx.getTypeSize(T);

  // CHECK: is SourceSize == TargetSize
  if (SourceSize == TargetSize)
    return;

  // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
  // otherwise generate a regular node.
  //
  // FIXME: We can actually create an abstract "CFNumber" object that has
  //  the bits initialized to the provided values.
  //
  if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() 
                                                : C.generateNode()) {
    llvm::SmallString<128> sbuf;
    llvm::raw_svector_ostream os(sbuf);
    
    os << (SourceSize == 8 ? "An " : "A ")
       << SourceSize << " bit integer is used to initialize a CFNumber "
                        "object that represents "
       << (TargetSize == 8 ? "an " : "a ")
       << TargetSize << " bit integer. ";
    
    if (SourceSize < TargetSize)
      os << (TargetSize - SourceSize)
      << " bits of the CFNumber value will be garbage." ;
    else
      os << (SourceSize - TargetSize)
      << " bits of the input integer will be lost.";

    if (!BT)
      BT = new APIMisuse("Bad use of CFNumberCreate");
    
    RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
    report->addRange(CE->getArg(2)->getSourceRange());
    C.EmitReport(report);
  }
}
Пример #13
0
bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, 
                                                 const CallExpr *CE) {
  // Not enough arguments to match OSAtomicCompareAndSwap?
  if (CE->getNumArgs() != 3)
    return false;

  ASTContext &Ctx = C.getASTContext();
  const Expr *oldValueExpr = CE->getArg(0);
  QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());

  const Expr *newValueExpr = CE->getArg(1);
  QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());

  // Do the types of 'oldValue' and 'newValue' match?
  if (oldValueType != newValueType)
    return false;

  const Expr *theValueExpr = CE->getArg(2);
  const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();

  // theValueType not a pointer?
  if (!theValueType)
    return false;

  QualType theValueTypePointee =
    Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();

  // The pointee must match newValueType and oldValueType.
  if (theValueTypePointee != newValueType)
    return false;

  static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
  static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
  
  // Load 'theValue'.
  ExprEngine &Engine = C.getEngine();
  const ProgramState *state = C.getState();
  ExplodedNodeSet Tmp;
  SVal location = state->getSVal(theValueExpr);
  // Here we should use the value type of the region as the load type, because
  // we are simulating the semantics of the function, not the semantics of 
  // passing argument. So the type of theValue expr is not we are loading.
  // But usually the type of the varregion is not the type we want either,
  // we still need to do a CastRetrievedVal in store manager. So actually this
  // LoadTy specifying can be omitted. But we put it here to emphasize the 
  // semantics.
  QualType LoadTy;
  if (const TypedValueRegion *TR =
      dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
    LoadTy = TR->getValueType();
  }
  Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(), 
                  state, location, &OSAtomicLoadTag, LoadTy);

  if (Tmp.empty()) {
    // If no nodes were generated, other checkers must generated sinks. But 
    // since the builder state was restored, we set it manually to prevent 
    // auto transition.
    // FIXME: there should be a better approach.
    C.getNodeBuilder().BuildSinks = true;
    return true;
  }
 
  for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
       I != E; ++I) {

    ExplodedNode *N = *I;
    const ProgramState *stateLoad = N->getState();

    // Use direct bindings from the environment since we are forcing a load
    // from a location that the Environment would typically not be used
    // to bind a value.
    SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, true);

    SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);

    // FIXME: Issue an error.
    if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
      return false;
    }
    
    DefinedOrUnknownSVal theValueVal =
      cast<DefinedOrUnknownSVal>(theValueVal_untested);
    DefinedOrUnknownSVal oldValueVal =
      cast<DefinedOrUnknownSVal>(oldValueVal_untested);

    SValBuilder &svalBuilder = Engine.getSValBuilder();

    // Perform the comparison.
    DefinedOrUnknownSVal Cmp =
      svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);

    const ProgramState *stateEqual = stateLoad->assume(Cmp, true);

    // Were they equal?
    if (stateEqual) {
      // Perform the store.
      ExplodedNodeSet TmpStore;
      SVal val = stateEqual->getSVal(newValueExpr);

      // Handle implicit value casts.
      if (const TypedValueRegion *R =
          dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
        val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
      }

      Engine.evalStore(TmpStore, NULL, theValueExpr, N, 
                       stateEqual, location, val, &OSAtomicStoreTag);

      if (TmpStore.empty()) {
        // If no nodes were generated, other checkers must generated sinks. But 
        // since the builder state was restored, we set it manually to prevent 
        // auto transition.
        // FIXME: there should be a better approach.
        C.getNodeBuilder().BuildSinks = true;
        return true;
      }

      // Now bind the result of the comparison.
      for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
           E2 = TmpStore.end(); I2 != E2; ++I2) {
        ExplodedNode *predNew = *I2;
        const ProgramState *stateNew = predNew->getState();
        // Check for 'void' return type if we have a bogus function prototype.
        SVal Res = UnknownVal();
        QualType T = CE->getType();
        if (!T->isVoidType())
          Res = Engine.getSValBuilder().makeTruthVal(true, T);
        C.generateNode(stateNew->BindExpr(CE, Res), predNew);
      }
    }

    // Were they not equal?
    if (const ProgramState *stateNotEqual = stateLoad->assume(Cmp, false)) {
      // Check for 'void' return type if we have a bogus function prototype.
      SVal Res = UnknownVal();
      QualType T = CE->getType();
      if (!T->isVoidType())
        Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType());
      C.generateNode(stateNotEqual->BindExpr(CE, Res), N);
    }
  }

  return true;
}
Пример #14
0
void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext,
                                        const Stmt *S,
                                        SVal location, bool isLoad) {

  // NOTE: Instead of using GRState::assumeInBound(), we are prototyping
  // some new logic here that reasons directly about memory region extents.
  // Once that logic is more mature, we can bring it back to assumeInBound()
  // for all clients to use.
  //
  // The algorithm we are using here for bounds checking is to see if the
  // memory access is within the extent of the base region.  Since we
  // have some flexibility in defining the base region, we can achieve
  // various levels of conservatism in our buffer overflow checking.
  const GRState *state = checkerContext.getState();  
  const GRState *originalState = state;

  SValBuilder &svalBuilder = checkerContext.getSValBuilder();
  const RegionRawOffsetV2 &rawOffset = 
    RegionRawOffsetV2::computeOffset(state, svalBuilder, location);

  if (!rawOffset.getRegion())
    return;

  // CHECK LOWER BOUND: Is byteOffset < 0?  If so, we are doing a load/store
  //  before the first valid offset in the memory region.

  SVal lowerBound
    = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(),
                              svalBuilder.makeZeroArrayIndex(),
                              svalBuilder.getConditionType());

  NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound);
  if (!lowerBoundToCheck)
    return;
    
  const GRState *state_precedesLowerBound, *state_withinLowerBound;
  llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
      state->assume(*lowerBoundToCheck);

  // Are we constrained enough to definitely precede the lower bound?
  if (state_precedesLowerBound && !state_withinLowerBound) {
    reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
    return;
  }
  
  // Otherwise, assume the constraint of the lower bound.
  assert(state_withinLowerBound);
  state = state_withinLowerBound;
  
  do {
    // CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)?  If so,
    // we are doing a load/store after the last valid offset.
    DefinedOrUnknownSVal extentVal =
      rawOffset.getRegion()->getExtent(svalBuilder);
    if (!isa<NonLoc>(extentVal))
      break;

    SVal upperbound
      = svalBuilder.evalBinOpNN(state, BO_GE, rawOffset.getByteOffset(),
                                cast<NonLoc>(extentVal),
                                svalBuilder.getConditionType());
  
    NonLoc *upperboundToCheck = dyn_cast<NonLoc>(&upperbound);
    if (!upperboundToCheck)
      break;
  
    const GRState *state_exceedsUpperBound, *state_withinUpperBound;
    llvm::tie(state_exceedsUpperBound, state_withinUpperBound) =
      state->assume(*upperboundToCheck);
  
    // Are we constrained enough to definitely exceed the upper bound?
    if (state_exceedsUpperBound && !state_withinUpperBound) {
      reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
      return;
    }
  
    assert(state_withinUpperBound);
    state = state_withinUpperBound;
  }
  while (false);
  
  if (state != originalState)
    checkerContext.generateNode(state);
}
void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
                                                    CheckerContext &C) const {
  if (!BT) {
    BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
                           "Objective-C pointer types"));

    ASTContext &Ctx = C.getASTContext();
    arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
    dictionaryWithObjectsAndKeysS = 
      GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
    setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);

    initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
    initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
  }

  if (!isVariadicMessage(msg))
      return;

  // We are not interested in the selector arguments since they have
  // well-defined types, so the compiler will issue a warning for them.
  unsigned variadicArgsBegin = msg.getSelector().getNumArgs();

  // We're not interested in the last argument since it has to be nil or the
  // compiler would have issued a warning for it elsewhere.
  unsigned variadicArgsEnd = msg.getNumArgs() - 1;

  if (variadicArgsEnd <= variadicArgsBegin)
    return;

  // Verify that all arguments have Objective-C types.
  llvm::Optional<ExplodedNode*> errorNode;
  const ProgramState *state = C.getState();
  
  for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
    QualType ArgTy = msg.getArgType(I);
    if (ArgTy->isObjCObjectPointerType())
      continue;

    // Block pointers are treaded as Objective-C pointers.
    if (ArgTy->isBlockPointerType())
      continue;

    // Ignore pointer constants.
    if (isa<loc::ConcreteInt>(msg.getArgSVal(I, state)))
      continue;
    
    // Ignore pointer types annotated with 'NSObject' attribute.
    if (C.getASTContext().isObjCNSObjectType(ArgTy))
      continue;
    
    // Ignore CF references, which can be toll-free bridged.
    if (coreFoundation::isCFObjectRef(ArgTy))
      continue;

    // Generate only one error node to use for all bug reports.
    if (!errorNode.hasValue()) {
      errorNode = C.generateNode();
    }

    if (!errorNode.getValue())
      continue;

    llvm::SmallString<128> sbuf;
    llvm::raw_svector_ostream os(sbuf);

    if (const char *TypeName = GetReceiverNameType(msg))
      os << "Argument to '" << TypeName << "' method '";
    else
      os << "Argument to method '";

    os << msg.getSelector().getAsString() 
      << "' should be an Objective-C pointer type, not '" 
      << ArgTy.getAsString() << "'";

    BugReport *R = new BugReport(*BT, os.str(),
                                             errorNode.getValue());
    R->addRange(msg.getArgSourceRange(I));
    C.EmitReport(R);
  }
}