Esempio n. 1
0
/// Returns the released value if M is a call a setter that releases
/// and nils out its underlying instance variable.
SymbolRef
ObjCDeallocChecker::getValueReleasedByNillingOut(const ObjCMethodCall &M,
                                                 CheckerContext &C) const {
  SVal ReceiverVal = M.getReceiverSVal();
  if (!ReceiverVal.isValid())
    return nullptr;

  if (M.getNumArgs() == 0)
    return nullptr;

  if (!M.getArgExpr(0)->getType()->isObjCRetainableType())
    return nullptr;

  // Is the first argument nil?
  SVal Arg = M.getArgSVal(0);
  ProgramStateRef notNilState, nilState;
  std::tie(notNilState, nilState) =
      M.getState()->assume(Arg.castAs<DefinedOrUnknownSVal>());
  if (!(nilState && !notNilState))
    return nullptr;

  const ObjCPropertyDecl *Prop = M.getAccessedProperty();
  if (!Prop)
    return nullptr;

  ObjCIvarDecl *PropIvarDecl = Prop->getPropertyIvarDecl();
  if (!PropIvarDecl)
    return nullptr;

  ProgramStateRef State = C.getState();

  SVal LVal = State->getLValue(PropIvarDecl, ReceiverVal);
  Optional<Loc> LValLoc = LVal.getAs<Loc>();
  if (!LValLoc)
    return nullptr;

  SVal CurrentValInIvar = State->getSVal(LValLoc.getValue());
  return CurrentValInIvar.getAsSymbol();
}
Esempio n. 2
0
/// Returns true if \param S is a DeclStmt for a local variable that
/// ObjC automated reference counting initialized with zero.
static bool isARCNilInitializedLocal(CheckerContext &C, const Stmt *S) {
  // We suppress diagnostics for ARC zero-initialized _Nonnull locals. This
  // prevents false positives when a _Nonnull local variable cannot be
  // initialized with an initialization expression:
  //    NSString * _Nonnull s; // no-warning
  //    @autoreleasepool {
  //      s = ...
  //    }
  //
  // FIXME: We should treat implicitly zero-initialized _Nonnull locals as
  // uninitialized in Sema's UninitializedValues analysis to warn when a use of
  // the zero-initialized definition will unexpectedly yield nil.

  // Locals are only zero-initialized when automated reference counting
  // is turned on.
  if (!C.getASTContext().getLangOpts().ObjCAutoRefCount)
    return false;

  auto *DS = dyn_cast<DeclStmt>(S);
  if (!DS || !DS->isSingleDecl())
    return false;

  auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
  if (!VD)
    return false;

  // Sema only zero-initializes locals with ObjCLifetimes.
  if(!VD->getType().getQualifiers().hasObjCLifetime())
    return false;

  const Expr *Init = VD->getInit();
  assert(Init && "ObjC local under ARC without initializer");

  // Return false if the local is explicitly initialized (e.g., with '= nil').
  if (!isa<ImplicitValueInitExpr>(Init))
    return false;

  return true;
}
Esempio n. 3
0
void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
                                            const BinaryOperator *B) {
  BinaryOperator::Opcode Op = B->getOpcode();
  if (Op != BO_Div &&
      Op != BO_Rem &&
      Op != BO_DivAssign &&
      Op != BO_RemAssign)
    return;

  if (!B->getRHS()->getType()->isIntegerType() ||
      !B->getRHS()->getType()->isScalarType())
    return;

  SVal Denom = C.getState()->getSVal(B->getRHS());
  const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);

  // Divide-by-undefined handled in the generic checking for uses of
  // undefined values.
  if (!DV)
    return;

  // Check for divide by zero.
  ConstraintManager &CM = C.getConstraintManager();
  const GRState *stateNotZero, *stateZero;
  llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);

  if (stateZero && !stateNotZero) {
    if (ExplodedNode *N = C.generateSink(stateZero)) {
      if (!BT)
        BT = new BuiltinBug("Division by zero");

      EnhancedBugReport *R = 
        new EnhancedBugReport(*BT, BT->getDescription(), N);

      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
                           bugreporter::GetDenomExpr(N));

      C.EmitReport(R);
    }
    return;
  }

  // If we get here, then the denom should not be zero. We abandon the implicit
  // zero denom case for now.
  C.addTransition(stateNotZero);
}
bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
  const ProgramState *state = C.getState();
  const Expr *Callee = CE->getCallee();
  SVal L = state->getSVal(Callee);

  const FunctionDecl *FD = L.getAsFunctionDecl();
  if (!FD)
    return false;

  const IdentifierInfo *II = FD->getIdentifier();
  if (!II)
    return false;
  
  StringRef FName(II->getName());

  // Check for compare and swap.
  if (FName.startswith("OSAtomicCompareAndSwap") ||
      FName.startswith("objc_atomicCompareAndSwap"))
    return evalOSAtomicCompareAndSwap(C, CE);

  // FIXME: Other atomics.
  return false;
}
Esempio n. 5
0
void MoveChecker::modelUse(ProgramStateRef State, const MemRegion *Region,
                           const CXXRecordDecl *RD, MisuseKind MK,
                           CheckerContext &C) const {
  assert(!C.isDifferent() && "No transitions should have been made by now");
  const RegionState *RS = State->get<TrackedRegionMap>(Region);
  ObjectKind OK = classifyObject(Region, RD);

  // Just in case: if it's not a smart pointer but it does have operator *,
  // we shouldn't call the bug a dereference.
  if (MK == MK_Dereference && OK.StdKind != SK_SmartPtr)
    MK = MK_FunCall;

  if (!RS || !shouldWarnAbout(OK, MK)
          || isInMoveSafeContext(C.getLocationContext())) {
    // Finalize changes made by the caller.
    C.addTransition(State);
    return;
  }

  // Don't report it in case if any base region is already reported.
  // But still generate a sink in case of UB.
  // And still finalize changes made by the caller.
  if (isAnyBaseRegionReported(State, Region)) {
    if (misuseCausesCrash(MK)) {
      C.generateSink(State, C.getPredecessor());
    } else {
      C.addTransition(State);
    }
    return;
  }

  ExplodedNode *N = reportBug(Region, RD, C, MK);

  // If the program has already crashed on this path, don't bother.
  if (N->isSink())
    return;

  State = State->set<TrackedRegionMap>(Region, RegionState::getReported());
  C.addTransition(State, N);
}
Esempio n. 6
0
void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
  // FIXME: Mostly copy and paste from UnixAPIChecker.  Should refactor.
  const GRState *state = C.getState();
  const Expr *Callee = CE->getCallee();
  const FunctionTextRegion *Fn =
    dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());

  if (!Fn)
    return;

  const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
  if (!FI)
    return;

  const SubCheck &SC =
    llvm::StringSwitch<SubCheck>(FI->getName())
      .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
      .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
                                        BTypes[DispatchOnceF]))
      .Default(SubCheck());

  SC.run(C, CE, FI);
}
void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
                                    CheckerContext &C) const {
  // FIXME: This sort of logic is common to several checkers, including
  // UnixAPIChecker, PthreadLockChecker, and CStringChecker.  Should refactor.
  const ProgramState *state = C.getState();
  const Expr *Callee = CE->getCallee();
  const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();

  if (!Fn)
    return;

  const IdentifierInfo *FI = Fn->getIdentifier();
  if (!FI)
    return;

  SubChecker SC =
    llvm::StringSwitch<SubChecker>(FI->getName())
      .Cases("dispatch_once", "dispatch_once_f",
             &MacOSXAPIChecker::CheckDispatchOnce)
      .Default(NULL);

  if (SC)
    (this->*SC)(C, CE, FI);
}
Esempio n. 8
0
void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
  // Get the callee.  All the functions we care about are C functions
  // with simple identifiers.
  const GRState *state = C.getState();
  const Expr *Callee = CE->getCallee();
  const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();

  if (!Fn)
    return;

  const IdentifierInfo *FI = Fn->getIdentifier();
  if (!FI)
    return;

  SubChecker SC =
    llvm::StringSwitch<SubChecker>(FI->getName())
      .Case("open", &UnixAPIChecker::CheckOpen)
      .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
      .Case("malloc", &UnixAPIChecker::CheckMallocZero)
      .Default(NULL);

  if (SC)
    (this->*SC)(C, CE);
}
Esempio n. 9
0
void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
                                        ObjCMessage msg)
{
  const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
  if (!ReceiverType)
    return;
  
  if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
    Selector S = msg.getSelector();
    
    if (S.isUnarySelector())
      return;
    
    // FIXME: This is going to be really slow doing these checks with
    //  lexical comparisons.
    
    std::string NameStr = S.getAsString();
    llvm::StringRef Name(NameStr);
    assert(!Name.empty());
    
    // FIXME: Checking for initWithFormat: will not work in most cases
    //  yet because [NSString alloc] returns id, not NSString*.  We will
    //  need support for tracking expected-type information in the analyzer
    //  to find these errors.
    if (Name == "caseInsensitiveCompare:" ||
        Name == "compare:" ||
        Name == "compare:options:" ||
        Name == "compare:options:range:" ||
        Name == "compare:options:range:locale:" ||
        Name == "componentsSeparatedByCharactersInSet:" ||
        Name == "initWithFormat:") {
      if (isNil(msg.getArgSVal(0, C.getState())))
        WarnNilArg(C, msg, 0);
    }
  }
}
Esempio n. 10
0
void ObjCSuperDeallocChecker::checkPreObjCMessage(const ObjCMethodCall &M,
                                                  CheckerContext &C) const {

  ProgramStateRef State = C.getState();
  SymbolRef ReceiverSymbol = M.getReceiverSVal().getAsSymbol();
  if (!ReceiverSymbol) {
    diagnoseCallArguments(M, C);
    return;
  }

  bool AlreadyCalled = State->contains<CalledSuperDealloc>(ReceiverSymbol);
  if (!AlreadyCalled)
    return;

  StringRef Desc;

  if (isSuperDeallocMessage(M)) {
    Desc = "[super dealloc] should not be called multiple times";
  } else {
    Desc = StringRef();
  }

  reportUseAfterDealloc(ReceiverSymbol, Desc, M.getOriginExpr(), C);
}
void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
                                  CheckerContext &C) const {
  BinaryOperator::Opcode Op = B->getOpcode();
  if (Op != BO_Div &&
      Op != BO_Rem &&
      Op != BO_DivAssign &&
      Op != BO_RemAssign)
    return;

  if (!B->getRHS()->getType()->isScalarType())
    return;

  SVal Denom = C.getState()->getSVal(B->getRHS(), C.getLocationContext());
  Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();

  // Divide-by-undefined handled in the generic checking for uses of
  // undefined values.
  if (!DV)
    return;

  // Check for divide by zero.
  ConstraintManager &CM = C.getConstraintManager();
  ProgramStateRef stateNotZero, stateZero;
  llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);

  if (!stateNotZero) {
    assert(stateZero);
    reportBug("Division by zero", stateZero, C);
    return;
  }

  bool TaintedD = C.getState()->isTainted(*DV);
  if ((stateNotZero && stateZero && TaintedD)) {
    reportBug("Division by a tainted value, possibly zero", stateZero, C);
    return;
  }

  // If we get here, then the denom should not be zero. We abandon the implicit
  // zero denom case for now.
  C.addTransition(stateNotZero);
}
void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
                                    CheckerContext &C) const {
    ProgramStateRef State = C.getState();

    // Check if this is the branch for the end of the loop.
    SVal CollectionSentinel = C.getSVal(FCS);
    if (CollectionSentinel.isZeroConstant()) {
        if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
            State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);

        // Otherwise, this is a branch that goes through the loop body.
    } else {
        State = checkCollectionNonNil(C, State, FCS);
        State = checkElementNonNil(C, State, FCS);
        State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
    }

    if (!State)
        C.generateSink();
    else if (State != C.getState())
        C.addTransition(State);
}
Esempio n. 13
0
void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
                                const SVal &RetVal, const SVal &Cont) const {
  const auto *ContReg = Cont.getAsRegion();
  if (!ContReg)
    return;

  while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
    ContReg = CBOR->getSuperRegion();
  }

  // If the container already has an end symbol then use it. Otherwise first
  // create a new one.
  auto State = C.getState();
  auto EndSym = getContainerEnd(State, ContReg);
  if (!EndSym) {
    auto &SymMgr = C.getSymbolManager();
    EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
                                  C.getASTContext().LongTy, C.blockCount());
    State = createContainerEnd(State, ContReg, EndSym);
  }
  State = setIteratorPosition(State, RetVal,
                              IteratorPosition::getPosition(ContReg, EndSym));
  C.addTransition(State);
}
Esempio n. 14
0
void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
                                              const CallExpr* CE) {
  // If the CallExpr doesn't have exactly 1 argument just give up checking.
  if (CE->getNumArgs() != 1)
    return;

  // Get the function declaration of the callee.
  const GRState* state = C.getState();
  SVal X = state->getSVal(CE->getCallee());
  const FunctionDecl* FD = X.getAsFunctionDecl();

  if (!FD)
    return;
  
  if (!BT) {
    ASTContext &Ctx = C.getASTContext();
    Retain = &Ctx.Idents.get("CFRetain");
    Release = &Ctx.Idents.get("CFRelease");
    BT = new APIMisuse("null passed to CFRetain/CFRelease");
  }

  // Check if we called CFRetain/CFRelease.
  const IdentifierInfo *FuncII = FD->getIdentifier();
  if (!(FuncII == Retain || FuncII == Release))
    return;

  // FIXME: The rest of this just checks that the argument is non-null.
  // It should probably be refactored and combined with AttrNonNullChecker.

  // Get the argument's value.
  const Expr *Arg = CE->getArg(0);
  SVal ArgVal = state->getSVal(Arg);
  DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
  if (!DefArgVal)
    return;

  // Get a NULL value.
  SValBuilder &svalBuilder = C.getSValBuilder();
  DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));

  // Make an expression asserting that they're equal.
  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);

  // Are they equal?
  const GRState *stateTrue, *stateFalse;
  llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);

  if (stateTrue && !stateFalse) {
    ExplodedNode *N = C.generateSink(stateTrue);
    if (!N)
      return;

    const char *description = (FuncII == Retain)
                            ? "Null pointer argument in call to CFRetain"
                            : "Null pointer argument in call to CFRelease";

    EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
    report->addRange(Arg->getSourceRange());
    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
    C.EmitReport(report);
    return;
  }

  // From here on, we know the argument is non-null.
  C.addTransition(stateFalse);
}
Esempio n. 15
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);
  }
}
Esempio n. 16
0
void NonNullParamChecker::checkPreCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  const Decl *FD = Call.getDecl();
  if (!FD)
    return;

  const NonNullAttr *Att = FD->getAttr<NonNullAttr>();

  ProgramStateRef state = C.getState();

  CallEvent::param_type_iterator TyI = Call.param_type_begin(),
                                 TyE = Call.param_type_end();

  for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx){

    // Check if the parameter is a reference. We want to report when reference
    // to a null pointer is passed as a paramter.
    bool haveRefTypeParam = false;
    if (TyI != TyE) {
      haveRefTypeParam = (*TyI)->isReferenceType();
      TyI++;
    }

    bool haveAttrNonNull = Att && Att->isNonNull(idx);
    if (!haveAttrNonNull) {
      // Check if the parameter is also marked 'nonnull'.
      ArrayRef<ParmVarDecl*> parms = Call.parameters();
      if (idx < parms.size())
        haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
    }

    if (!haveRefTypeParam && !haveAttrNonNull)
      continue;

    // If the value is unknown or undefined, we can't perform this check.
    const Expr *ArgE = Call.getArgExpr(idx);
    SVal V = Call.getArgSVal(idx);
    Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
    if (!DV)
      continue;

    // Process the case when the argument is not a location.
    assert(!haveRefTypeParam || DV->getAs<Loc>());

    if (haveAttrNonNull && !DV->getAs<Loc>()) {
      // If the argument is a union type, we want to handle a potential
      // transparent_union GCC extension.
      if (!ArgE)
        continue;

      QualType T = ArgE->getType();
      const RecordType *UT = T->getAsUnionType();
      if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
        continue;

      if (Optional<nonloc::CompoundVal> CSV =
              DV->getAs<nonloc::CompoundVal>()) {
        nonloc::CompoundVal::iterator CSV_I = CSV->begin();
        assert(CSV_I != CSV->end());
        V = *CSV_I;
        DV = V.getAs<DefinedSVal>();
        assert(++CSV_I == CSV->end());
        // FIXME: Handle (some_union){ some_other_union_val }, which turns into
        // a LazyCompoundVal inside a CompoundVal.
        if (!V.getAs<Loc>())
          continue;
        // Retrieve the corresponding expression.
        if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
          if (const InitListExpr *IE =
                dyn_cast<InitListExpr>(CE->getInitializer()))
             ArgE = dyn_cast<Expr>(*(IE->begin()));

      } else {
        // FIXME: Handle LazyCompoundVals?
        continue;
      }
    }

    ConstraintManager &CM = C.getConstraintManager();
    ProgramStateRef stateNotNull, stateNull;
    std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);

    if (stateNull && !stateNotNull) {
      // Generate an error node.  Check for a null node in case
      // we cache out.
      if (ExplodedNode *errorNode = C.generateSink(stateNull)) {

        BugReport *R = 0;
        if (haveAttrNonNull)
          R = genReportNullAttrNonNull(errorNode, ArgE);
        else if (haveRefTypeParam)
          R = genReportReferenceToNullPointer(errorNode, ArgE);

        // Highlight the range of the argument that was null.
        R->addRange(Call.getArgSourceRange(idx));

        // Emit the bug report.
        C.emitReport(R);
      }

      // Always return.  Either we cached out or we just emitted an error.
      return;
    }

    // If a pointer value passed the check we should assume that it is
    // indeed not null from this point forward.
    assert(stateNotNull);
    state = stateNotNull;
  }

  // If we reach here all of the arguments passed the nonnull check.
  // If 'state' has been updated generated a new node.
  C.addTransition(state);
}
Esempio n. 17
0
void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
    const GRState *state = C.getState();
    if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
        return;
}
void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                        CheckerContext &C) const {
  const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
  if (!ID)
    return;

  FoundationClass Class = findKnownClass(ID);

  static const unsigned InvalidArgIndex = UINT_MAX;
  unsigned Arg = InvalidArgIndex;
  bool CanBeSubscript = false;

  if (Class == FC_NSString) {
    Selector S = msg.getSelector();

    if (S.isUnarySelector())
      return;

    if (StringSelectors.empty()) {
      ASTContext &Ctx = C.getASTContext();
      Selector Sels[] = {
        getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
        getKeywordSelector(Ctx, "compare", nullptr),
        getKeywordSelector(Ctx, "compare", "options", nullptr),
        getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
        getKeywordSelector(Ctx, "compare", "options", "range", "locale",
                           nullptr),
        getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
                           nullptr),
        getKeywordSelector(Ctx, "initWithFormat",
                           nullptr),
        getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
        getKeywordSelector(Ctx, "localizedCompare", nullptr),
        getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
      };
      for (Selector KnownSel : Sels)
        StringSelectors[KnownSel] = 0;
    }
    auto I = StringSelectors.find(S);
    if (I == StringSelectors.end())
      return;
    Arg = I->second;
  } else if (Class == FC_NSArray) {
    Selector S = msg.getSelector();

    if (S.isUnarySelector())
      return;

    if (ArrayWithObjectSel.isNull()) {
      ASTContext &Ctx = C.getASTContext();
      ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
      AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
      InsertObjectAtIndexSel =
        getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
      ReplaceObjectAtIndexWithObjectSel =
        getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
      SetObjectAtIndexedSubscriptSel =
        getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
      ArrayByAddingObjectSel =
        getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
    }

    if (S == ArrayWithObjectSel || S == AddObjectSel ||
        S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
      Arg = 0;
    } else if (S == SetObjectAtIndexedSubscriptSel) {
      Arg = 0;
      CanBeSubscript = true;
    } else if (S == ReplaceObjectAtIndexWithObjectSel) {
      Arg = 1;
    }
  } else if (Class == FC_NSDictionary) {
    Selector S = msg.getSelector();

    if (S.isUnarySelector())
      return;

    if (DictionaryWithObjectForKeySel.isNull()) {
      ASTContext &Ctx = C.getASTContext();
      DictionaryWithObjectForKeySel =
        getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
      SetObjectForKeySel =
        getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
      SetObjectForKeyedSubscriptSel =
        getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
      RemoveObjectForKeySel =
        getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
    }

    if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
      Arg = 0;
      warnIfNilArg(C, msg, /* Arg */1, Class);
    } else if (S == SetObjectForKeyedSubscriptSel) {
      CanBeSubscript = true;
      Arg = 0;
      warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
    } else if (S == RemoveObjectForKeySel) {
      Arg = 0;
    }
  }

  // If argument is '0', report a warning.
  if ((Arg != InvalidArgIndex))
    warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
}
Esempio n. 19
0
void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
  // The definition of O_CREAT is platform specific.  We need a better way
  // of querying this information from the checking environment.
  if (!Val_O_CREAT.hasValue()) {
    if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
      Val_O_CREAT = 0x0200;
    else {
      // FIXME: We need a more general way of getting the O_CREAT value.
      // We could possibly grovel through the preprocessor state, but
      // that would require passing the Preprocessor object to the ExprEngine.
      return;
    }
  }

  // Look at the 'oflags' argument for the O_CREAT flag.
  const GRState *state = C.getState();

  if (CE->getNumArgs() < 2) {
    // The frontend should issue a warning for this case, so this is a sanity
    // check.
    return;
  }

  // Now check if oflags has O_CREAT set.
  const Expr *oflagsEx = CE->getArg(1);
  const SVal V = state->getSVal(oflagsEx);
  if (!isa<NonLoc>(V)) {
    // The case where 'V' can be a location can only be due to a bad header,
    // so in this case bail out.
    return;
  }
  NonLoc oflags = cast<NonLoc>(V);
  NonLoc ocreateFlag =
    cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(),
                                                oflagsEx->getType()));
  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
                                                      oflags, ocreateFlag,
                                                      oflagsEx->getType());
  if (maskedFlagsUC.isUnknownOrUndef())
    return;
  DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);

  // Check if maskedFlags is non-zero.
  const GRState *trueState, *falseState;
  llvm::tie(trueState, falseState) = state->assume(maskedFlags);

  // Only emit an error if the value of 'maskedFlags' is properly
  // constrained;
  if (!(trueState && !falseState))
    return;

  if (CE->getNumArgs() < 3) {
    ExplodedNode *N = C.generateSink(trueState);
    if (!N)
      return;

    LazyInitialize(BT_open, "Improper use of 'open'");

    RangedBugReport *report =
      new RangedBugReport(*BT_open,
                            "Call to 'open' requires a third argument when "
                            "the 'O_CREAT' flag is set", N);
    report->addRange(oflagsEx->getSourceRange());
    C.EmitReport(report);
  }
}
Esempio n. 20
0
void IteratorChecker::checkPostCall(const CallEvent &Call,
                                    CheckerContext &C) const {
  // Record new iterator positions and iterator position changes
  const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
  if (!Func)
    return;

  if (Func->isOverloadedOperator()) {
    const auto Op = Func->getOverloadedOperator();
    if (isSimpleComparisonOperator(Op)) {
      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
        handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
                         Call.getArgSVal(0), Op);
      } else {
        handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
                         Call.getArgSVal(1), Op);
      }
    }
  } else {
    const auto *OrigExpr = Call.getOriginExpr();
    if (!OrigExpr)
      return;

    if (!isIteratorType(Call.getResultType()))
      return;

    auto State = C.getState();
    // Already bound to container?
    if (getIteratorPosition(State, Call.getReturnValue()))
      return;

    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
      if (isEndCall(Func)) {
        handleEnd(C, OrigExpr, Call.getReturnValue(),
                  InstCall->getCXXThisVal());
        return;
      }
    }

    // Copy-like and move constructors
    if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
      if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
        State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
        if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
          State = removeIteratorPosition(State, Call.getArgSVal(0));
        }
        C.addTransition(State);
        return;
      }
    }

    // Assumption: if return value is an iterator which is not yet bound to a
    //             container, then look for the first iterator argument, and
    //             bind the return value to the same container. This approach
    //             works for STL algorithms.
    // FIXME: Add a more conservative mode
    for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
      if (isIteratorType(Call.getArgExpr(i)->getType())) {
        if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
          assignToContainer(C, OrigExpr, Call.getReturnValue(),
                            Pos->getContainer());
          return;
        }
      }
    }
  }
}
Esempio n. 21
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);
}
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);
}
Esempio n. 23
0
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
                                               SVal V, SourceRange argRange,
                                               const Expr *argEx,
                                               const char *BT_desc,
                                               llvm::OwningPtr<BugType> &BT) {

  if (V.isUndef()) {
    if (ExplodedNode *N = C.generateSink()) {
      LazyInit_BT(BT_desc, BT);

      // Generate a report for this bug.
      BugReport *R = new BugReport(*BT, BT->getName(), N);
      R->addRange(argRange);
      if (argEx)
        R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx));
      C.EmitReport(R);
    }
    return true;
  }

  if (const nonloc::LazyCompoundVal *LV =
        dyn_cast<nonloc::LazyCompoundVal>(&V)) {

    class FindUninitializedField {
    public:
      SmallVector<const FieldDecl *, 10> FieldChain;
    private:
      ASTContext &C;
      StoreManager &StoreMgr;
      MemRegionManager &MrMgr;
      Store store;
    public:
      FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
                             MemRegionManager &mrMgr, Store s)
      : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}

      bool Find(const TypedValueRegion *R) {
        QualType T = R->getValueType();
        if (const RecordType *RT = T->getAsStructureType()) {
          const RecordDecl *RD = RT->getDecl()->getDefinition();
          assert(RD && "Referred record has no definition");
          for (RecordDecl::field_iterator I =
               RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
            const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
            FieldChain.push_back(*I);
            T = (*I)->getType();
            if (T->getAsStructureType()) {
              if (Find(FR))
                return true;
            }
            else {
              const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
              if (V.isUndef())
                return true;
            }
            FieldChain.pop_back();
          }
        }

        return false;
      }
    };

    const LazyCompoundValData *D = LV->getCVData();
    FindUninitializedField F(C.getASTContext(),
                             C.getState()->getStateManager().getStoreManager(),
                             C.getSValBuilder().getRegionManager(),
                             D->getStore());

    if (F.Find(D->getRegion())) {
      if (ExplodedNode *N = C.generateSink()) {
        LazyInit_BT(BT_desc, BT);
        llvm::SmallString<512> Str;
        llvm::raw_svector_ostream os(Str);
        os << "Passed-by-value struct argument contains uninitialized data";

        if (F.FieldChain.size() == 1)
          os << " (e.g., field: '" << *F.FieldChain[0] << "')";
        else {
          os << " (e.g., via the field chain: '";
          bool first = true;
          for (SmallVectorImpl<const FieldDecl *>::iterator
               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
            if (first)
              first = false;
            else
              os << '.';
            os << **DI;
          }
          os << "')";
        }

        // Generate a report for this bug.
        BugReport *R = new BugReport(*BT, os.str(), N);
        R->addRange(argRange);

        // FIXME: enhance track back for uninitialized value for arbitrary
        // memregions
        C.EmitReport(R);
      }
      return true;
    }
  }

  return false;
}
void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
                                          CheckerContext &C) const {
  // If the CallExpr doesn't have exactly 1 argument just give up checking.
  if (CE->getNumArgs() != 1)
    return;

  ProgramStateRef state = C.getState();
  const FunctionDecl *FD = C.getCalleeDecl(CE);
  if (!FD)
    return;

  if (!BT) {
    ASTContext &Ctx = C.getASTContext();
    Retain = &Ctx.Idents.get("CFRetain");
    Release = &Ctx.Idents.get("CFRelease");
    MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
    Autorelease = &Ctx.Idents.get("CFAutorelease");
    BT.reset(new APIMisuse(
        this, "null passed to CF memory management function"));
  }

  // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
  const IdentifierInfo *FuncII = FD->getIdentifier();
  if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
        FuncII == Autorelease))
    return;

  // FIXME: The rest of this just checks that the argument is non-null.
  // It should probably be refactored and combined with NonNullParamChecker.

  // Get the argument's value.
  const Expr *Arg = CE->getArg(0);
  SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
  if (!DefArgVal)
    return;

  // Get a NULL value.
  SValBuilder &svalBuilder = C.getSValBuilder();
  DefinedSVal zero =
      svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();

  // Make an expression asserting that they're equal.
  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);

  // Are they equal?
  ProgramStateRef stateTrue, stateFalse;
  std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);

  if (stateTrue && !stateFalse) {
    ExplodedNode *N = C.generateErrorNode(stateTrue);
    if (!N)
      return;

    const char *description;
    if (FuncII == Retain)
      description = "Null pointer argument in call to CFRetain";
    else if (FuncII == Release)
      description = "Null pointer argument in call to CFRelease";
    else if (FuncII == MakeCollectable)
      description = "Null pointer argument in call to CFMakeCollectable";
    else if (FuncII == Autorelease)
      description = "Null pointer argument in call to CFAutorelease";
    else
      llvm_unreachable("impossible case");

    auto report = llvm::make_unique<BugReport>(*BT, description, N);
    report->addRange(Arg->getSourceRange());
    bugreporter::trackNullOrUndefValue(N, Arg, *report);
    C.emitReport(std::move(report));
    return;
  }

  // From here on, we know the argument is non-null.
  C.addTransition(stateFalse);
}
void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
                                         CheckerContext &C) const {
  ProgramStateRef state = C.getState();
  const FunctionDecl *FD = C.getCalleeDecl(CE);
  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.
  const LocationContext *LCtx = C.getLocationContext();
  SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);

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

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

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

  uint64_t TargetSize = *OptTargetSize;

  // 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), LCtx);

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

  const TypedValueRegion* R = dyn_cast<TypedValueRegion>(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->isIntegralOrEnumerationType())
    return;

  uint64_t SourceSize = Ctx.getTypeSize(T);

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

  // Generate an error.  Only generate a sink error node
  // if 'SourceSize < TargetSize'; otherwise generate a non-fatal error node.
  //
  // FIXME: We can actually create an abstract "CFNumber" object that has
  //  the bits initialized to the provided values.
  //
  ExplodedNode *N = SourceSize < TargetSize ? C.generateErrorNode()
                                            : C.generateNonFatalErrorNode();
  if (N) {
    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.reset(new APIMisuse(this, "Bad use of CFNumberCreate"));

    auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
    report->addRange(CE->getArg(2)->getSourceRange());
    C.emitReport(std::move(report));
  }
}
Esempio n. 26
0
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
                                   CheckerContext &C, bool IsBind) const {
  // Generate an error node.
  ExplodedNode *N = C.generateSink(State);
  if (!N)
    return;

  // We know that 'location' cannot be non-null.  This is what
  // we call an "explicit" null dereference.
  if (!BT_null)
    BT_null.reset(new BuiltinBug("Dereference of null pointer"));

  SmallString<100> buf;
  SmallVector<SourceRange, 2> Ranges;

  // Walk through lvalue casts to get the original expression
  // that syntactically caused the load.
  if (const Expr *expr = dyn_cast<Expr>(S))
    S = expr->IgnoreParenLValueCasts();

  const MemRegion *sourceR = 0;

  if (IsBind) {
    if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
      if (BO->isAssignmentOp())
        S = BO->getRHS();
    } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
      assert(DS->isSingleDecl() && "We process decls one by one");
      if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
        if (const Expr *Init = VD->getAnyInitializer())
          S = Init;
    }
  }

  switch (S->getStmtClass()) {
  case Stmt::ArraySubscriptExprClass: {
    llvm::raw_svector_ostream os(buf);
    os << "Array access";
    const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
    sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
                             State.getPtr(), N->getLocationContext());
    os << " results in a null pointer dereference";
    break;
  }
  case Stmt::UnaryOperatorClass: {
    llvm::raw_svector_ostream os(buf);
    os << "Dereference of null pointer";
    const UnaryOperator *U = cast<UnaryOperator>(S);
    sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
                             State.getPtr(), N->getLocationContext(), true);
    break;
  }
  case Stmt::MemberExprClass: {
    const MemberExpr *M = cast<MemberExpr>(S);
    if (M->isArrow()) {
      llvm::raw_svector_ostream os(buf);
      os << "Access to field '" << M->getMemberNameInfo()
         << "' results in a dereference of a null pointer";
      sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
                               State.getPtr(), N->getLocationContext(), true);
    }
    break;
  }
  case Stmt::ObjCIvarRefExprClass: {
    const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
    if (const DeclRefExpr *DR =
        dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
        llvm::raw_svector_ostream os(buf);
        os << "Instance variable access (via '" << VD->getName()
           << "') results in a null pointer dereference";
      }
    }
    Ranges.push_back(IV->getSourceRange());
    break;
  }
  default:
    break;
  }

  BugReport *report =
    new BugReport(*BT_null,
                  buf.empty() ? BT_null->getDescription() : buf.str(),
                  N);

  bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N),
                                               report);

  for (SmallVectorImpl<SourceRange>::iterator
       I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
    report->addRange(*I);

  if (sourceR) {
    report->markInteresting(sourceR);
    report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR)));
  }

  C.EmitReport(report);
}
void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                                    CheckerContext &C) const {
  if (!BT) {
    BT.reset(new APIMisuse(this,
                           "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);
    orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", 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.
  Optional<ExplodedNode*> errorNode;

  for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
    QualType ArgTy = msg.getArgExpr(I)->getType();
    if (ArgTy->isObjCObjectPointerType())
      continue;

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

    // Ignore pointer constants.
    if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
      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.generateNonFatalErrorNode();

    if (!errorNode.getValue())
      continue;

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

    StringRef TypeName = GetReceiverInterfaceName(msg);
    if (!TypeName.empty())
      os << "Argument to '" << TypeName << "' method '";
    else
      os << "Argument to method '";

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

    auto R = llvm::make_unique<BugReport>(*BT, os.str(), errorNode.getValue());
    R->addRange(msg.getArgSourceRange(I));
    C.emitReport(std::move(R));
  }
}
Esempio n. 28
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;
}
Esempio n. 29
0
static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C) {
  // We tag the symbol that the SVal wraps.
  if (SymbolRef sym = val.getAsSymbol())
    C.addTransition(state->set<T>(sym, true));
}
Esempio n. 30
0
void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
  ProgramStateRef state = C.getState();

  if (CE->getNumArgs() < 2) {
    // The frontend should issue a warning for this case, so this is a sanity
    // check.
    return;
  } else if (CE->getNumArgs() == 3) {
    const Expr *Arg = CE->getArg(2);
    QualType QT = Arg->getType();
    if (!QT->isIntegerType()) {
      ReportOpenBug(C, state,
                    "Third argument to 'open' is not an integer",
                    Arg->getSourceRange());
      return;
    }
  } else if (CE->getNumArgs() > 3) {
    ReportOpenBug(C, state,
                  "Call to 'open' with more than three arguments",
                  CE->getArg(3)->getSourceRange());
    return;
  }

  // The definition of O_CREAT is platform specific.  We need a better way
  // of querying this information from the checking environment.
  if (!Val_O_CREAT.hasValue()) {
    if (C.getASTContext().getTargetInfo().getTriple().getVendor()
                                                      == llvm::Triple::Apple)
      Val_O_CREAT = 0x0200;
    else {
      // FIXME: We need a more general way of getting the O_CREAT value.
      // We could possibly grovel through the preprocessor state, but
      // that would require passing the Preprocessor object to the ExprEngine.
      // See also: MallocChecker.cpp / M_ZERO.
      return;
    }
  }

  // Now check if oflags has O_CREAT set.
  const Expr *oflagsEx = CE->getArg(1);
  const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
  if (!V.getAs<NonLoc>()) {
    // The case where 'V' can be a location can only be due to a bad header,
    // so in this case bail out.
    return;
  }
  NonLoc oflags = V.castAs<NonLoc>();
  NonLoc ocreateFlag = C.getSValBuilder()
      .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
                                                      oflags, ocreateFlag,
                                                      oflagsEx->getType());
  if (maskedFlagsUC.isUnknownOrUndef())
    return;
  DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();

  // Check if maskedFlags is non-zero.
  ProgramStateRef trueState, falseState;
  std::tie(trueState, falseState) = state->assume(maskedFlags);

  // Only emit an error if the value of 'maskedFlags' is properly
  // constrained;
  if (!(trueState && !falseState))
    return;

  if (CE->getNumArgs() < 3) {
    ReportOpenBug(C, trueState,
                  "Call to 'open' requires a third argument when "
                  "the 'O_CREAT' flag is set",
                  oflagsEx->getSourceRange());
  }
}