Пример #1
0
// FIXME: This is the sort of code that should eventually live in a Core
// checker rather than as a special case in ExprEngine.
void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
                                    const CallEvent &Call) {
  SVal ThisVal;
  bool AlwaysReturnsLValue;
  const CXXRecordDecl *ThisRD = nullptr;
  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
    assert(Ctor->getDecl()->isTrivial());
    assert(Ctor->getDecl()->isCopyOrMoveConstructor());
    ThisVal = Ctor->getCXXThisVal();
    ThisRD = Ctor->getDecl()->getParent();
    AlwaysReturnsLValue = false;
  } else {
    assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
    assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
           OO_Equal);
    ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
    ThisRD = cast<CXXMethodDecl>(Call.getDecl())->getParent();
    AlwaysReturnsLValue = true;
  }

  assert(ThisRD);
  if (ThisRD->isEmpty()) {
    // Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal
    // and bind it and RegionStore would think that the actual value
    // in this region at this offset is unknown.
    return;
  }

  const LocationContext *LCtx = Pred->getLocationContext();

  ExplodedNodeSet Dst;
  Bldr.takeNodes(Pred);

  SVal V = Call.getArgSVal(0);

  // If the value being copied is not unknown, load from its location to get
  // an aggregate rvalue.
  if (Optional<Loc> L = V.getAs<Loc>())
    V = Pred->getState()->getSVal(*L);
  else
    assert(V.isUnknownOrUndef());

  const Expr *CallExpr = Call.getOriginExpr();
  evalBind(Dst, CallExpr, Pred, ThisVal, V, true);

  PostStmt PS(CallExpr, LCtx);
  for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end();
       I != E; ++I) {
    ProgramStateRef State = (*I)->getState();
    if (AlwaysReturnsLValue)
      State = State->BindExpr(CallExpr, LCtx, ThisVal);
    else
      State = bindReturnValue(Call, LCtx, State);
    Bldr.generateNode(PS, State, *I);
  }
}
Пример #2
0
void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
                                         CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  // If this is a call to a C++ method, check if the callee is null or
  // undefined.
  if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
    SVal V = CC->getCXXThisVal();
    if (V.isUndef()) {
      if (!BT_cxx_call_undef)
        BT_cxx_call_undef.reset(new BuiltinBug("Called C++ object pointer is "
                                               "uninitialized"));
      emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
      return;
    }

    ProgramStateRef StNonNull, StNull;
    llvm::tie(StNonNull, StNull) =
        State->assume(V.castAs<DefinedOrUnknownSVal>());

    if (StNull && !StNonNull) {
      if (!BT_cxx_call_null)
        BT_cxx_call_null.reset(new BuiltinBug("Called C++ object pointer "
                                              "is null"));
      emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
      return;
    }

    State = StNonNull;
  }

  // Don't check for uninitialized field values in arguments if the
  // caller has a body that is available and we have the chance to inline it.
  // This is a hack, but is a reasonable compromise betweens sometimes warning
  // and sometimes not depending on if we decide to inline a function.
  const Decl *D = Call.getDecl();
  const bool checkUninitFields =
    !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));

  OwningPtr<BugType> *BT;
  if (isa<ObjCMethodCall>(Call))
    BT = &BT_msg_arg;
  else
    BT = &BT_call_arg;

  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
    if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
                           Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
                           checkUninitFields, Call, *BT))
      return;

  // If we make it here, record our assumptions about the callee.
  C.addTransition(State);
}
void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
        CheckerContext &C) const {
    ProgramStateRef state = C.getState();
    bool BuildSinks = false;

    if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
        BuildSinks = FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();

    const Expr *Callee = CE.getOriginExpr();
    if (!BuildSinks && Callee)
        BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();

    if (!BuildSinks && CE.isGlobalCFunction()) {
        if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
            // HACK: Some functions are not marked noreturn, and don't return.
            //  Here are a few hardwired ones.  If this takes too long, we can
            //  potentially cache these results.
            BuildSinks
                = llvm::StringSwitch<bool>(StringRef(II->getName()))
                  .Case("exit", true)
                  .Case("panic", true)
                  .Case("error", true)
                  .Case("Assert", true)
                  // FIXME: This is just a wrapper around throwing an exception.
                  //  Eventually inter-procedural analysis should handle this easily.
                  .Case("ziperr", true)
                  .Case("assfail", true)
                  .Case("db_error", true)
                  .Case("__assert", true)
                  // For the purpose of static analysis, we do not care that
                  //  this MSVC function will return if the user decides to continue.
                  .Case("_wassert", true)
                  .Case("__assert_rtn", true)
                  .Case("__assert_fail", true)
                  .Case("dtrace_assfail", true)
                  .Case("yy_fatal_error", true)
                  .Case("_XCAssertionFailureHandler", true)
                  .Case("_DTAssertionFailureHandler", true)
                  .Case("_TSAssertionFailureHandler", true)
                  .Default(false);
        }
    }

    if (BuildSinks)
        C.generateSink();
}
Пример #4
0
// FIXME: This is the sort of code that should eventually live in a Core
// checker rather than as a special case in ExprEngine.
void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
                                    const CallEvent &Call) {
  SVal ThisVal;
  bool AlwaysReturnsLValue;
  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
    assert(Ctor->getDecl()->isTrivial());
    assert(Ctor->getDecl()->isCopyOrMoveConstructor());
    ThisVal = Ctor->getCXXThisVal();
    AlwaysReturnsLValue = false;
  } else {
    assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
    assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
           OO_Equal);
    ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
    AlwaysReturnsLValue = true;
  }

  const LocationContext *LCtx = Pred->getLocationContext();

  ExplodedNodeSet Dst;
  Bldr.takeNodes(Pred);

  SVal V = Call.getArgSVal(0);

  // If the value being copied is not unknown, load from its location to get
  // an aggregate rvalue.
  if (Optional<Loc> L = V.getAs<Loc>())
    V = Pred->getState()->getSVal(*L);
  else
    assert(V.isUnknown());

  const Expr *CallExpr = Call.getOriginExpr();
  evalBind(Dst, CallExpr, Pred, ThisVal, V, true);

  PostStmt PS(CallExpr, LCtx);
  for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end();
       I != E; ++I) {
    ProgramStateRef State = (*I)->getState();
    if (AlwaysReturnsLValue)
      State = State->BindExpr(CallExpr, LCtx, ThisVal);
    else
      State = bindReturnValue(Call, LCtx, State);
    Bldr.generateNode(PS, State, *I);
  }
}
/// \return Bitvector marking non-null attributes.
static llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) {
  const Decl *FD = Call.getDecl();
  unsigned NumArgs = Call.getNumArgs();
  llvm::SmallBitVector AttrNonNull(NumArgs);
  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
    if (!NonNull->args_size()) {
      AttrNonNull.set(0, NumArgs);
      break;
    }
    for (const ParamIdx &Idx : NonNull->args()) {
      unsigned IdxAST = Idx.getASTIndex();
      if (IdxAST >= NumArgs)
        continue;
      AttrNonNull.set(IdxAST);
    }
  }
  return AttrNonNull;
}
Пример #6
0
void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
                                         CheckerContext &C) const {
  // If this is a call to a C++ method, check if the callee is null or
  // undefined.
  // FIXME: Generalize this to CXXInstanceCall once it supports
  // getCXXThisVal().
  if (const CXXMemberCall *CC = dyn_cast<CXXMemberCall>(&Call)) {
    SVal V = CC->getCXXThisVal();
    if (V.isUndef()) {
      if (!BT_cxx_call_undef)
        BT_cxx_call_undef.reset(new BuiltinBug("Called C++ object pointer is "
                                               "uninitialized"));
      EmitBadCall(BT_cxx_call_undef.get(), C, CC->getOriginExpr());
      return;
    }
    if (V.isZeroConstant()) {
      if (!BT_cxx_call_null)
        BT_cxx_call_null.reset(new BuiltinBug("Called C++ object pointer "
                                              "is null"));
      EmitBadCall(BT_cxx_call_null.get(), C, CC->getOriginExpr());
      return;
    }
  }

  // Don't check for uninitialized field values in arguments if the
  // caller has a body that is available and we have the chance to inline it.
  // This is a hack, but is a reasonable compromise betweens sometimes warning
  // and sometimes not depending on if we decide to inline a function.
  const Decl *D = Call.getDecl();
  const bool checkUninitFields =
    !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));

  OwningPtr<BugType> *BT;
  if (isa<ObjCMethodCall>(Call))
    BT = &BT_msg_arg;
  else
    BT = &BT_call_arg;

  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
    if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
                           Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
                           checkUninitFields, Call, *BT))
      return;
}
Пример #7
0
void IteratorChecker::checkPreCall(const CallEvent &Call,
                                   CheckerContext &C) const {
  // Check for out of range access
  const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
  if (!Func)
    return;

  if (Func->isOverloadedOperator()) {
    if (ChecksEnabled[CK_IteratorRangeChecker] &&
               isDereferenceOperator(Func->getOverloadedOperator())) {
      // Check for dereference of out-of-range iterators
      if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
        verifyDereference(C, InstCall->getCXXThisVal());
      } else {
        verifyDereference(C, Call.getArgSVal(0));
      }
    }
  }
}
void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
                                          CheckerContext &C) const {
  // TODO: Make this check part of CallDescription.
  if (!Call.isGlobalCFunction())
    return;

  // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
  if (!(Call.isCalled(CFRetain) || Call.isCalled(CFRelease) ||
        Call.isCalled(CFMakeCollectable) || Call.isCalled(CFAutorelease)))
    return;

  // Get the argument's value.
  SVal ArgVal = Call.getArgSVal(0);
  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
  if (!DefArgVal)
    return;

  // Is it null?
  ProgramStateRef state = C.getState();
  ProgramStateRef stateNonNull, stateNull;
  std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal);

  if (!stateNonNull) {
    ExplodedNode *N = C.generateErrorNode(stateNull);
    if (!N)
      return;

    SmallString<64> Str;
    raw_svector_ostream OS(Str);
    OS << "Null pointer argument in call to "
       << cast<FunctionDecl>(Call.getDecl())->getName();

    auto report = llvm::make_unique<BugReport>(BT, OS.str(), N);
    report->addRange(Call.getArgSourceRange(0));
    bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
    C.emitReport(std::move(report));
    return;
  }

  // From here on, we know the argument is non-null.
  C.addTransition(stateNonNull);
}
Пример #9
0
/// Suppress the nullability warnings for some functions.
void NullabilityChecker::checkPostCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  auto Decl = Call.getDecl();
  if (!Decl)
    return;
  // ObjC Messages handles in a different callback.
  if (Call.getKind() == CE_ObjCMessage)
    return;
  const FunctionType *FuncType = Decl->getFunctionType();
  if (!FuncType)
    return;
  QualType ReturnType = FuncType->getReturnType();
  if (!ReturnType->isAnyPointerType())
    return;
  ProgramStateRef State = C.getState();
  if (State->get<PreconditionViolated>())
    return;

  const MemRegion *Region = getTrackRegion(Call.getReturnValue());
  if (!Region)
    return;

  // CG headers are misannotated. Do not warn for symbols that are the results
  // of CG calls.
  const SourceManager &SM = C.getSourceManager();
  StringRef FilePath = SM.getFilename(SM.getSpellingLoc(Decl->getLocStart()));
  if (llvm::sys::path::filename(FilePath).startswith("CG")) {
    State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
    C.addTransition(State);
    return;
  }

  const NullabilityState *TrackedNullability =
      State->get<NullabilityMap>(Region);

  if (!TrackedNullability &&
      getNullabilityAnnotation(ReturnType) == Nullability::Nullable) {
    State = State->set<NullabilityMap>(Region, Nullability::Nullable);
    C.addTransition(State);
  }
}
Пример #10
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);
}
bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
                            const CallEvent &Call,
                            ExplodedNode *Pred) {
    if (!getAnalysisManager().shouldInlineCall())
        return false;

    const StackFrameContext *CallerSFC =
        Pred->getLocationContext()->getCurrentStackFrame();

    const Decl *D = Call.getDecl();
    const LocationContext *ParentOfCallee = 0;

    switch (Call.getKind()) {
    case CE_Function:
    case CE_CXXMember:
        // These are always at least possible to inline.
        break;
    case CE_CXXMemberOperator:
        // FIXME: This should be possible to inline, but
        // RegionStore::enterStackFrame isn't smart enough to handle the first
        // argument being 'this'. The correct solution is to use CallEvent in
        // enterStackFrame as well.
        return false;
    case CE_CXXConstructor:
        // Do not inline constructors until we can model destructors.
        // This is unfortunate, but basically necessary for smart pointers and such.
        return false;
    case CE_CXXAllocator:
        // Do not inline allocators until we model deallocators.
        // This is unfortunate, but basically necessary for smart pointers and such.
        return false;
    case CE_Block: {
        const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
        if (!BR)
            return false;
        D = BR->getDecl();
        AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
        ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
                         cast<BlockDecl>(D),
                         BR);
        break;
    }
    case CE_ObjCMessage:
    case CE_ObjCPropertyAccess:
        // These always use dynamic dispatch; enabling inlining means assuming
        // that a particular method will be called at runtime.
        return false;
    }

    if (!D || !shouldInlineDecl(D, Pred))
        return false;

    if (!ParentOfCallee)
        ParentOfCallee = CallerSFC;

    const Expr *CallE = Call.getOriginExpr();
    assert(CallE && "It is not yet possible to have calls without statements");

    // Construct a new stack frame for the callee.
    AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
    const StackFrameContext *CalleeSFC =
        CalleeADC->getStackFrame(ParentOfCallee, CallE,
                                 currentBuilderContext->getBlock(),
                                 currentStmtIdx);

    CallEnter Loc(CallE, CalleeSFC, Pred->getLocationContext());
    bool isNew;
    if (ExplodedNode *N = G.getNode(Loc, Pred->getState(), false, &isNew)) {
        N->addPredecessor(Pred, G);
        if (isNew)
            Engine.getWorkList()->enqueue(N);
    }
    return true;
}
Пример #12
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;
        }
      }
    }
  }
}
void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
                                         CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  // If this is a call to a C++ method, check if the callee is null or
  // undefined.
  if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
    SVal V = CC->getCXXThisVal();
    if (V.isUndef()) {
      if (!BT_cxx_call_undef)
        BT_cxx_call_undef.reset(
            new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
      emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
      return;
    }

    ProgramStateRef StNonNull, StNull;
    std::tie(StNonNull, StNull) =
        State->assume(V.castAs<DefinedOrUnknownSVal>());

    if (StNull && !StNonNull) {
      if (!BT_cxx_call_null)
        BT_cxx_call_null.reset(
            new BuiltinBug(this, "Called C++ object pointer is null"));
      emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
      return;
    }

    State = StNonNull;
  }

  const Decl *D = Call.getDecl();
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
  if (FD) {
    // If we have a declaration, we can make sure we pass enough parameters to
    // the function.
    unsigned Params = FD->getNumParams();
    if (Call.getNumArgs() < Params) {
      ExplodedNode *N = C.generateSink();
      if (!N)
        return;

      LazyInit_BT("Function call with too few arguments", BT_call_few_args);

      SmallString<512> Str;
      llvm::raw_svector_ostream os(Str);
      os << "Function taking " << Params << " argument"
         << (Params == 1 ? "" : "s") << " is called with less ("
         << Call.getNumArgs() << ")";

      C.emitReport(
          llvm::make_unique<BugReport>(*BT_call_few_args, os.str(), N));
    }
  }

  // Don't check for uninitialized field values in arguments if the
  // caller has a body that is available and we have the chance to inline it.
  // This is a hack, but is a reasonable compromise betweens sometimes warning
  // and sometimes not depending on if we decide to inline a function.
  const bool checkUninitFields =
    !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));

  std::unique_ptr<BugType> *BT;
  if (isa<ObjCMethodCall>(Call))
    BT = &BT_msg_arg;
  else
    BT = &BT_call_arg;

  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
    const ParmVarDecl *ParamDecl = nullptr;
    if(FD && i < FD->getNumParams())
      ParamDecl = FD->getParamDecl(i);
    if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
                           Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
                           checkUninitFields, Call, *BT, ParamDecl))
      return;
  }

  // If we make it here, record our assumptions about the callee.
  C.addTransition(State);
}
Пример #14
0
void AttrNonNullChecker::checkPreCall(const CallEvent &Call,
                                      CheckerContext &C) const {
  const Decl *FD = Call.getDecl();
  if (!FD)
    return;

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

  ProgramStateRef state = C.getState();

  // Iterate through the arguments of CE and check them for null.
  for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx) {
    if (!Att->isNonNull(idx))
      continue;

    SVal V = Call.getArgSVal(idx);
    DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);

    // If the value is unknown or undefined, we can't perform this check.
    if (!DV)
      continue;

    if (!isa<Loc>(*DV)) {
      // If the argument is a union type, we want to handle a potential
      // transparent_union GCC extension.
      const Expr *ArgE = Call.getArgExpr(idx);
      if (!ArgE)
        continue;

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

      if (nonloc::CompoundVal *CSV = dyn_cast<nonloc::CompoundVal>(DV)) {
        nonloc::CompoundVal::iterator CSV_I = CSV->begin();
        assert(CSV_I != CSV->end());
        V = *CSV_I;
        DV = dyn_cast<DefinedSVal>(&V);
        assert(++CSV_I == CSV->end());
        if (!DV)
          continue;        
      } else {
        // FIXME: Handle LazyCompoundVals?
        continue;
      }
    }

    ConstraintManager &CM = C.getConstraintManager();
    ProgramStateRef stateNotNull, stateNull;
    llvm::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)) {

        // Lazily allocate the BugType object if it hasn't already been
        // created. Ownership is transferred to the BugReporter object once
        // the BugReport is passed to 'EmitWarning'.
        if (!BT)
          BT.reset(new BugType("Argument with 'nonnull' attribute passed null",
                               "API"));

        BugReport *R =
          new BugReport(*BT, "Null pointer passed as an argument to a "
                             "'nonnull' parameter", errorNode);

        // Highlight the range of the argument that was null.
        R->addRange(Call.getArgSourceRange(idx));
        if (const Expr *ArgE = Call.getArgExpr(idx))
          bugreporter::addTrackNullOrUndefValueVisitor(errorNode, ArgE, R);
        // 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);
}
void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call,
                                             CheckerContext &C) const {
  ProgramStateRef State = C.getState();
  const LocationContext *LC = C.getLocationContext();
  ExplodedNode *N = nullptr;

  // Remove the MemRegions from the map on which a ctor/dtor call or assignement
  // happened.

  // Checking constructor calls.
  if (const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
    State = removeFromState(State, CC->getCXXThisVal().getAsRegion());
    auto CtorDec = CC->getDecl();
    // Check for copying a moved-from object and report the bug.
    if (CtorDec && CtorDec->isCopyOrMoveConstructor()) {
      const MemRegion *ArgRegion = CC->getArgSVal(0).getAsRegion();
      const RegionState *ArgState = State->get<TrackedRegionMap>(ArgRegion);
      if (ArgState && ArgState->isMoved()) {
        if (!isInMoveSafeContext(LC)) {
          N = reportBug(ArgRegion, Call, C, /*isCopy=*/true);
          State = State->set<TrackedRegionMap>(ArgRegion,
                                               RegionState::getReported());
        }
      }
    }
    C.addTransition(State, N);
    return;
  }

  const auto IC = dyn_cast<CXXInstanceCall>(&Call);
  if (!IC)
    return;
  // In case of destructor call we do not track the object anymore.
  const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
  if (dyn_cast_or_null<CXXDestructorDecl>(Call.getDecl())) {
    State = removeFromState(State, IC->getCXXThisVal().getAsRegion());
    C.addTransition(State);
    return;
  }

  const auto MethodDecl = dyn_cast_or_null<CXXMethodDecl>(IC->getDecl());
  if (!MethodDecl)
    return;
  // Checking assignment operators.
  bool OperatorEq = MethodDecl->isOverloadedOperator() &&
                    MethodDecl->getOverloadedOperator() == OO_Equal;
  // Remove the tracked object for every assignment operator, but report bug
  // only for move or copy assignment's argument.
  if (OperatorEq) {
    State = removeFromState(State, ThisRegion);
    if (MethodDecl->isCopyAssignmentOperator() ||
        MethodDecl->isMoveAssignmentOperator()) {
      const RegionState *ArgState =
          State->get<TrackedRegionMap>(IC->getArgSVal(0).getAsRegion());
      if (ArgState && ArgState->isMoved() && !isInMoveSafeContext(LC)) {
        const MemRegion *ArgRegion = IC->getArgSVal(0).getAsRegion();
        N = reportBug(ArgRegion, Call, C, /*isCopy=*/true);
        State =
            State->set<TrackedRegionMap>(ArgRegion, RegionState::getReported());
      }
    }
    C.addTransition(State, N);
    return;
  }

  // The remaining part is check only for method call on a moved-from object.
  if (isMoveSafeMethod(MethodDecl))
    return;

  if (isStateResetMethod(MethodDecl)) {
    State = State->remove<TrackedRegionMap>(ThisRegion);
    C.addTransition(State);
    return;
  }

  // If it is already reported then we dont report the bug again.
  const RegionState *ThisState = State->get<TrackedRegionMap>(ThisRegion);
  if (!(ThisState && ThisState->isMoved()))
    return;

  // Dont report it in case if any base region is already reported
  if (isAnyBaseRegionReported(State, ThisRegion))
    return;

  if (isInMoveSafeContext(LC))
    return;

  N = reportBug(ThisRegion, Call, C);
  State = State->set<TrackedRegionMap>(ThisRegion, RegionState::getReported());
  C.addTransition(State, N);
}
void NonNullParamChecker::checkPreCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  if (!Call.getDecl())
    return;

  llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call);
  unsigned NumArgs = Call.getNumArgs();

  ProgramStateRef state = C.getState();
  ArrayRef<ParmVarDecl*> parms = Call.parameters();

  for (unsigned idx = 0; idx < NumArgs; ++idx) {
    // For vararg functions, a corresponding parameter decl may not exist.
    bool HasParam = idx < parms.size();

    // Check if the parameter is a reference. We want to report when reference
    // to a null pointer is passed as a parameter.
    bool haveRefTypeParam =
        HasParam ? parms[idx]->getType()->isReferenceType() : false;
    bool haveAttrNonNull = AttrNonNull[idx];

    // Check if the parameter is also marked 'nonnull'.
    if (!haveAttrNonNull && HasParam)
      haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();

    if (!haveAttrNonNull && !haveRefTypeParam)
      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);
    auto DV = V.getAs<DefinedSVal>();
    if (!DV)
      continue;

    assert(!haveRefTypeParam || DV->getAs<Loc>());

    // Process the case when the argument is not a location.
    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;

      auto CSV = DV->getAs<nonloc::CompoundVal>();

      // FIXME: Handle LazyCompoundVals?
      if (!CSV)
        continue;

      V = *(CSV->begin());
      DV = V.getAs<DefinedSVal>();
      assert(++CSV->begin() == 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 auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
        if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
          ArgE = dyn_cast<Expr>(*(IE->begin()));
    }

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

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

        std::unique_ptr<BugReport> R;
        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(std::move(R));
      }

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

    if (stateNull) {
      if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
        ImplicitNullDerefEvent event = {
          V, false, N, &C.getBugReporter(),
          /*IsDirectDereference=*/haveRefTypeParam};
        dispatchEvent(event);
      }
    }

    // If a pointer value passed the check we should assume that it is
    // indeed not null from this point forward.
    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);
}
Пример #17
0
/// This callback warns when a nullable pointer or a null value is passed to a
/// function that expects its argument to be nonnull.
void NullabilityChecker::checkPreCall(const CallEvent &Call,
                                      CheckerContext &C) const {
  if (!Call.getDecl())
    return;

  ProgramStateRef State = C.getState();
  if (State->get<PreconditionViolated>())
    return;

  ProgramStateRef OrigState = State;

  unsigned Idx = 0;
  for (const ParmVarDecl *Param : Call.parameters()) {
    if (Param->isParameterPack())
      break;

    const Expr *ArgExpr = nullptr;
    if (Idx < Call.getNumArgs())
      ArgExpr = Call.getArgExpr(Idx);
    auto ArgSVal = Call.getArgSVal(Idx++).getAs<DefinedOrUnknownSVal>();
    if (!ArgSVal)
      continue;

    if (!Param->getType()->isAnyPointerType() &&
        !Param->getType()->isReferenceType())
      continue;

    NullConstraint Nullness = getNullConstraint(*ArgSVal, State);

    Nullability ParamNullability = getNullabilityAnnotation(Param->getType());
    Nullability ArgStaticNullability =
        getNullabilityAnnotation(ArgExpr->getType());

    if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
        ArgStaticNullability != Nullability::Nonnull &&
        ParamNullability == Nullability::Nonnull) {
      ExplodedNode *N = C.generateErrorNode(State);
      if (!N)
        return;
      reportBugIfPreconditionHolds(ErrorKind::NilPassedToNonnull, N, nullptr, C,
                                   ArgExpr);
      return;
    }

    const MemRegion *Region = getTrackRegion(*ArgSVal);
    if (!Region)
      continue;

    const NullabilityState *TrackedNullability =
        State->get<NullabilityMap>(Region);

    if (TrackedNullability) {
      if (Nullness == NullConstraint::IsNotNull ||
          TrackedNullability->getValue() != Nullability::Nullable)
        continue;

      if (Filter.CheckNullablePassedToNonnull &&
          ParamNullability == Nullability::Nonnull) {
        ExplodedNode *N = C.addTransition(State);
        reportBugIfPreconditionHolds(ErrorKind::NullablePassedToNonnull, N,
                                     Region, C, ArgExpr, /*SuppressPath=*/true);
        return;
      }
      if (Filter.CheckNullableDereferenced &&
          Param->getType()->isReferenceType()) {
        ExplodedNode *N = C.addTransition(State);
        reportBugIfPreconditionHolds(ErrorKind::NullableDereferenced, N, Region,
                                     C, ArgExpr, /*SuppressPath=*/true);
        return;
      }
      continue;
    }
    // No tracked nullability yet.
    if (ArgStaticNullability != Nullability::Nullable)
      continue;
    State = State->set<NullabilityMap>(
        Region, NullabilityState(ArgStaticNullability, ArgExpr));
  }
  if (State != OrigState)
    C.addTransition(State);
}
/// This callback warns when a nullable pointer or a null value is passed to a
/// function that expects its argument to be nonnull.
void NullabilityChecker::checkPreCall(const CallEvent &Call,
                                      CheckerContext &C) const {
  if (!Call.getDecl())
    return;

  ProgramStateRef State = C.getState();
  if (State->get<InvariantViolated>())
    return;

  ProgramStateRef OrigState = State;

  unsigned Idx = 0;
  for (const ParmVarDecl *Param : Call.parameters()) {
    if (Param->isParameterPack())
      break;

    if (Idx >= Call.getNumArgs())
      break;

    const Expr *ArgExpr = Call.getArgExpr(Idx);
    auto ArgSVal = Call.getArgSVal(Idx++).getAs<DefinedOrUnknownSVal>();
    if (!ArgSVal)
      continue;

    if (!Param->getType()->isAnyPointerType() &&
        !Param->getType()->isReferenceType())
      continue;

    NullConstraint Nullness = getNullConstraint(*ArgSVal, State);

    Nullability RequiredNullability =
        getNullabilityAnnotation(Param->getType());
    Nullability ArgExprTypeLevelNullability =
        getNullabilityAnnotation(ArgExpr->getType());

    unsigned ParamIdx = Param->getFunctionScopeIndex() + 1;

    if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
        ArgExprTypeLevelNullability != Nullability::Nonnull &&
        RequiredNullability == Nullability::Nonnull &&
        isDiagnosableCall(Call)) {
      ExplodedNode *N = C.generateErrorNode(State);
      if (!N)
        return;

      SmallString<256> SBuf;
      llvm::raw_svector_ostream OS(SBuf);
      OS << (Param->getType()->isObjCObjectPointerType() ? "nil" : "Null");
      OS << " passed to a callee that requires a non-null " << ParamIdx
         << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
      reportBugIfInvariantHolds(OS.str(), ErrorKind::NilPassedToNonnull, N,
                                nullptr, C,
                                ArgExpr, /*SuppressPath=*/false);
      return;
    }

    const MemRegion *Region = getTrackRegion(*ArgSVal);
    if (!Region)
      continue;

    const NullabilityState *TrackedNullability =
        State->get<NullabilityMap>(Region);

    if (TrackedNullability) {
      if (Nullness == NullConstraint::IsNotNull ||
          TrackedNullability->getValue() != Nullability::Nullable)
        continue;

      if (Filter.CheckNullablePassedToNonnull &&
          RequiredNullability == Nullability::Nonnull &&
          isDiagnosableCall(Call)) {
        ExplodedNode *N = C.addTransition(State);
        SmallString<256> SBuf;
        llvm::raw_svector_ostream OS(SBuf);
        OS << "Nullable pointer is passed to a callee that requires a non-null "
           << ParamIdx << llvm::getOrdinalSuffix(ParamIdx) << " parameter";
        reportBugIfInvariantHolds(OS.str(),
                                  ErrorKind::NullablePassedToNonnull, N,
                                  Region, C, ArgExpr, /*SuppressPath=*/true);
        return;
      }
      if (Filter.CheckNullableDereferenced &&
          Param->getType()->isReferenceType()) {
        ExplodedNode *N = C.addTransition(State);
        reportBugIfInvariantHolds("Nullable pointer is dereferenced",
                                  ErrorKind::NullableDereferenced, N, Region,
                                  C, ArgExpr, /*SuppressPath=*/true);
        return;
      }
      continue;
    }
    // No tracked nullability yet.
    if (ArgExprTypeLevelNullability != Nullability::Nullable)
      continue;
    State = State->set<NullabilityMap>(
        Region, NullabilityState(ArgExprTypeLevelNullability, ArgExpr));
  }
  if (State != OrigState)
    C.addTransition(State);
}