diff options
22 files changed, 304 insertions, 240 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerV2.h b/clang/include/clang/StaticAnalyzer/Core/CheckerV2.h index a4c7c7d8060..07f1109864f 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerV2.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerV2.h @@ -15,6 +15,7 @@  #define LLVM_CLANG_SA_CORE_CHECKERV2  #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"  #include "llvm/Support/Casting.h"  namespace clang { @@ -358,6 +359,14 @@ public:    }  }; +/// \brief We dereferenced a location that may be null. +struct ImplicitNullDerefEvent { +  SVal Location; +  bool IsLoad; +  ExplodedNode *SinkNode; +  BugReporter *BR; +}; +  } // end ento namespace  } // end clang namespace diff --git a/clang/lib/StaticAnalyzer/Checkers/Checkers.td b/clang/lib/StaticAnalyzer/Checkers/Checkers.td index 99556847b56..4dec676404e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/lib/StaticAnalyzer/Checkers/Checkers.td @@ -70,11 +70,19 @@ def ObjCMethSigsChecker : Checker<"MethodSigs">,  def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">,    HelpText<"Warn about private ivars that are never used">,    DescFile<"ObjCUnusedIVarsChecker.cpp">; +  +def NSErrorChecker : Checker<"NSError">, +  HelpText<"Check usage of NSError** parameters">, +  DescFile<"NSErrorChecker.cpp">;  } // end "cocoa"  let ParentPackage = Core in { +def DereferenceChecker : Checker<"Deref">, +  HelpText<"Check for null pointers at loads and stores">, +  DescFile<"DereferenceChecker.cpp">; +  def CallAndMessageChecker : Checker<"CallAndMsg">,    HelpText<"Check for errors of call and objc message expressions">,    DescFile<"CallAndMessageChecker.cpp">; @@ -162,6 +170,11 @@ def CFRetainReleaseChecker : Checker<"CFRetainRelease">,    HelpText<"Check for null arguments to CFRetain/CFRelease">,    DescFile<"BasicObjCFoundationChecks.cpp">; +def CFErrorChecker : Checker<"CFError">, +  InPackage<MacOSX>, +  HelpText<"Check usage of CFErrorRef* parameters">, +  DescFile<"NSErrorChecker.cpp">; +  def LLVMConventionsChecker : Checker<"Conventions">,    InPackage<LLVM>,    HelpText<"Check code for LLVM codebase conventions">, diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 606ac4ab4e4..11a20d39abd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -12,51 +12,31 @@  //  //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"  #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"  using namespace clang;  using namespace ento;  namespace { -class DereferenceChecker : public Checker { -  BuiltinBug *BT_null; -  BuiltinBug *BT_undef; -  llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes; +class DereferenceChecker +    : public CheckerV2< check::Location, +                        EventDispatcher<ImplicitNullDerefEvent> > { +  mutable llvm::OwningPtr<BuiltinBug> BT_null; +  mutable llvm::OwningPtr<BuiltinBug> BT_undef; +  public: -  DereferenceChecker() : BT_null(0), BT_undef(0) {} -  static void *getTag() { static int tag = 0; return &tag; } -  void visitLocation(CheckerContext &C, const Stmt *S, SVal location, -                     bool isLoad); - -  std::pair<ExplodedNode * const*, ExplodedNode * const*> -  getImplicitNodes() const { -    return std::make_pair(ImplicitNullDerefNodes.data(), -                          ImplicitNullDerefNodes.data() + -                          ImplicitNullDerefNodes.size()); -  } -  void AddDerefSource(llvm::raw_ostream &os, -                      llvm::SmallVectorImpl<SourceRange> &Ranges, -                      const Expr *Ex, bool loadedFrom = false); +  void checkLocation(SVal location, bool isLoad, CheckerContext &C) const; + +  static void AddDerefSource(llvm::raw_ostream &os, +                             llvm::SmallVectorImpl<SourceRange> &Ranges, +                             const Expr *Ex, bool loadedFrom = false);  };  } // end anonymous namespace -void ento::RegisterDereferenceChecker(ExprEngine &Eng) { -  Eng.registerCheck(new DereferenceChecker()); -} - -std::pair<ExplodedNode * const *, ExplodedNode * const *> -ento::GetImplicitNullDereferences(ExprEngine &Eng) { -  DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>(); -  if (!checker) -    return std::make_pair((ExplodedNode * const *) 0, -                          (ExplodedNode * const *) 0); -  return checker->getImplicitNodes(); -} -  void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,                                       llvm::SmallVectorImpl<SourceRange> &Ranges,                                          const Expr *Ex, @@ -85,13 +65,13 @@ void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,    }  } -void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S, -                                       SVal l, bool isLoad) { +void DereferenceChecker::checkLocation(SVal l, bool isLoad, +                                       CheckerContext &C) const {    // Check for dereference of an undefined value.    if (l.isUndef()) {      if (ExplodedNode *N = C.generateSink()) {        if (!BT_undef) -        BT_undef = new BuiltinBug("Dereference of undefined pointer value"); +        BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value"));        EnhancedBugReport *report =          new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); @@ -108,6 +88,7 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,    if (!isa<Loc>(location))      return; +  const Stmt *S = C.getStmt();    const GRState *state = C.getState();    const GRState *notNullState, *nullState;    llvm::tie(notNullState, nullState) = state->assume(location); @@ -123,7 +104,7 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,        // We know that 'location' cannot be non-null.  This is what        // we call an "explicit" null dereference.        if (!BT_null) -        BT_null = new BuiltinBug("Dereference of null pointer"); +        BT_null.reset(new BuiltinBug("Dereference of null pointer"));        llvm::SmallString<100> buf;        llvm::SmallVector<SourceRange, 2> Ranges; @@ -195,11 +176,17 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,        // Otherwise, we have the case where the location could either be        // null or not-null.  Record the error node as an "implicit" null        // dereference. -      if (ExplodedNode *N = C.generateSink(nullState)) -        ImplicitNullDerefNodes.push_back(N); +      if (ExplodedNode *N = C.generateSink(nullState)) { +        ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() }; +        dispatchEvent(event); +      }      }    }    // From this point forward, we know that the location is not null.    C.addTransition(notNullState);  } + +void ento::registerDereferenceChecker(CheckerManager &mgr) { +  mgr.registerChecker<DereferenceChecker>(); +} diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 5b8bd18d817..552ca7d84a2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -308,22 +308,6 @@ void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,  // Engine construction and deletion.  //===----------------------------------------------------------------------===// -static void RegisterInternalChecks(ExprEngine &Eng) { -  // Register internal "built-in" BugTypes with the BugReporter. These BugTypes -  // are different than what probably many checks will do since they don't -  // create BugReports on-the-fly but instead wait until ExprEngine finishes -  // analyzing a function.  Generation of BugReport objects is done via a call -  // to 'FlushReports' from BugReporter. -  // The following checks do not need to have their associated BugTypes -  // explicitly registered with the BugReporter.  If they issue any BugReports, -  // their associated BugType will get registered with the BugReporter -  // automatically.  Note that the check itself is owned by the ExprEngine -  // object. -  // CallAndMessageChecker should be registered before AttrNonNullChecker, -  // where we assume arguments are not undefined. -  RegisterDereferenceChecker(Eng); -} -  ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)    : AMgr(mgr),      Engine(*this), @@ -338,8 +322,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)      NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),      RaiseSel(GetNullarySelector("raise", getContext())),      BR(mgr, *this), TF(tf) { -  // Register internal checks. -  RegisterInternalChecks(*this);    // FIXME: Eventually remove the TF object entirely.    TF->RegisterChecks(*this); diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 7a1b9787754..ed7094f1247 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -1,4 +1,4 @@ -//=- NSErrorCheckerer.cpp - Coding conventions for uses of NSError -*- C++ -*-==// +//=- NSErrorChecker.cpp - Coding conventions for uses of NSError -*- C++ -*-==//  //  //                     The LLVM Compiler Infrastructure  // @@ -15,11 +15,12 @@  //  //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"  #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h" -#include "BasicObjCFoundationChecks.h"  #include "clang/AST/DeclObjC.h"  #include "clang/AST/Decl.h"  #include "llvm/ADT/SmallVector.h" @@ -27,142 +28,248 @@  using namespace clang;  using namespace ento; -namespace { -class NSErrorChecker : public BugType { -  const Decl &CodeDecl; -  const bool isNSErrorWarning; -  IdentifierInfo * const II; -  ExprEngine &Eng; +static bool IsNSError(const ParmVarDecl *PD, IdentifierInfo *II); +static bool IsCFError(const ParmVarDecl *PD, IdentifierInfo *II); -  void CheckSignature(const ObjCMethodDecl& MD, QualType& ResultTy, -                      llvm::SmallVectorImpl<VarDecl*>& ErrorParams); +//===----------------------------------------------------------------------===// +// NSErrorMethodChecker +//===----------------------------------------------------------------------===// -  void CheckSignature(const FunctionDecl& MD, QualType& ResultTy, -                      llvm::SmallVectorImpl<VarDecl*>& ErrorParams); +namespace { +class NSErrorMethodChecker +    : public CheckerV2< check::ASTDecl<ObjCMethodDecl> > { +  mutable IdentifierInfo *II; -  bool CheckNSErrorArgument(QualType ArgTy); -  bool CheckCFErrorArgument(QualType ArgTy); +public: +  NSErrorMethodChecker() : II(0) { } -  void CheckParamDeref(const VarDecl *V, const LocationContext *LC, -                       const GRState *state, BugReporter& BR); +  void checkASTDecl(const ObjCMethodDecl *D, +                    AnalysisManager &mgr, BugReporter &BR) const; +}; +} -  void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl); +void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D, +                                        AnalysisManager &mgr, +                                        BugReporter &BR) const { +  if (!D->isThisDeclarationADefinition()) +    return; +  if (!D->getResultType()->isVoidType()) +    return; -public: -  NSErrorChecker(const Decl &D, bool isNSError, ExprEngine& eng) -    : BugType(isNSError ? "NSError** null dereference" -                        : "CFErrorRef* null dereference", -              "Coding conventions (Apple)"), -    CodeDecl(D), -    isNSErrorWarning(isNSError), -    II(&eng.getContext().Idents.get(isNSErrorWarning ? "NSError":"CFErrorRef")), -    Eng(eng) {} - -  void FlushReports(BugReporter& BR); -}; +  if (!II) +    II = &D->getASTContext().Idents.get("NSError");  -} // end anonymous namespace +  bool hasNSError = false; +  for (ObjCMethodDecl::param_iterator +         I = D->param_begin(), E = D->param_end(); I != E; ++I)  { +    if (IsNSError(*I, II)) { +      hasNSError = true; +      break; +    } +  } -void ento::RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng, -                                  const Decl &D) { -  BR.Register(new NSErrorChecker(D, true, Eng)); -  BR.Register(new NSErrorChecker(D, false, Eng)); +  if (hasNSError) { +    const char *err = "Method accepting NSError** " +        "should have a non-void return value to indicate whether or not an " +        "error occurred"; +    BR.EmitBasicReport("Bad return type when passing NSError**", +                       "Coding conventions (Apple)", err, D->getLocation()); +  }  } -void NSErrorChecker::FlushReports(BugReporter& BR) { -  // Get the analysis engine and the exploded analysis graph. -  ExplodedGraph& G = Eng.getGraph(); +//===----------------------------------------------------------------------===// +// CFErrorFunctionChecker +//===----------------------------------------------------------------------===// -  // Get the ASTContext, which is useful for querying type information. -  ASTContext &Ctx = BR.getContext(); +namespace { +class CFErrorFunctionChecker +    : public CheckerV2< check::ASTDecl<FunctionDecl> > { +  mutable IdentifierInfo *II; -  QualType ResultTy; -  llvm::SmallVector<VarDecl*, 5> ErrorParams; +public: +  CFErrorFunctionChecker() : II(0) { } -  if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl)) -    CheckSignature(*MD, ResultTy, ErrorParams); -  else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(&CodeDecl)) -    CheckSignature(*FD, ResultTy, ErrorParams); -  else -    return; +  void checkASTDecl(const FunctionDecl *D, +                    AnalysisManager &mgr, BugReporter &BR) const; +}; +} -  if (ErrorParams.empty()) +void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, +                                        AnalysisManager &mgr, +                                        BugReporter &BR) const { +  if (!D->isThisDeclarationADefinition()) +    return; +  if (!D->getResultType()->isVoidType())      return; -  if (ResultTy == Ctx.VoidTy) EmitRetTyWarning(BR, CodeDecl); +  if (!II) +    II = &D->getASTContext().Idents.get("CFErrorRef");  -  for (ExplodedGraph::roots_iterator RI=G.roots_begin(), RE=G.roots_end(); -       RI!=RE; ++RI) { -    // Scan the parameters for an implicit null dereference. -    for (llvm::SmallVectorImpl<VarDecl*>::iterator I=ErrorParams.begin(), -          E=ErrorParams.end(); I!=E; ++I) -        CheckParamDeref(*I, (*RI)->getLocationContext(), (*RI)->getState(), BR); +  bool hasCFError = false; +  for (FunctionDecl::param_const_iterator +         I = D->param_begin(), E = D->param_end(); I != E; ++I)  { +    if (IsCFError(*I, II)) { +      hasCFError = true; +      break; +    } +  } + +  if (hasCFError) { +    const char *err = "Function accepting CFErrorRef* " +        "should have a non-void return value to indicate whether or not an " +        "error occurred"; +    BR.EmitBasicReport("Bad return type when passing CFErrorRef*", +                       "Coding conventions (Apple)", err, D->getLocation());    }  } -void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { -  std::string sbuf; -  llvm::raw_string_ostream os(sbuf); +//===----------------------------------------------------------------------===// +// NSOrCFErrorDerefChecker +//===----------------------------------------------------------------------===// -  if (isa<ObjCMethodDecl>(CodeDecl)) -    os << "Method"; -  else -    os << "Function"; +namespace { -  os << " accepting "; -  os << (isNSErrorWarning ? "NSError**" : "CFErrorRef*"); -  os << " should have a non-void return value to indicate whether or not an " -        "error occurred"; +class NSErrorDerefBug : public BugType { +public: +  NSErrorDerefBug() : BugType("NSError** null dereference", +                              "Coding conventions (Apple)") {} +}; -  BR.EmitBasicReport(isNSErrorWarning -                     ? "Bad return type when passing NSError**" -                     : "Bad return type when passing CFError*", -                     getCategory(), os.str(), -                     CodeDecl.getLocation()); +class CFErrorDerefBug : public BugType { +public: +  CFErrorDerefBug() : BugType("CFErrorRef* null dereference", +                              "Coding conventions (Apple)") {} +}; + +} + +namespace { +class NSOrCFErrorDerefChecker +    : public CheckerV2< check::Location, +                        check::Event<ImplicitNullDerefEvent> > { +  mutable IdentifierInfo *NSErrorII, *CFErrorII; +public: +  bool ShouldCheckNSError, ShouldCheckCFError; +  NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0), +                              ShouldCheckNSError(0), ShouldCheckCFError(0) { } + +  void checkLocation(SVal loc, bool isLoad, CheckerContext &C) const; +  void checkEvent(ImplicitNullDerefEvent event) const; +}; +} + +namespace { struct NSErrorOut {}; } +namespace { struct CFErrorOut {}; } + +typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag; + +namespace clang { +namespace ento { +  template <> +  struct GRStateTrait<NSErrorOut> : public GRStatePartialTrait<ErrorOutFlag> {   +    static void *GDMIndex() { static int index = 0; return &index; } +  }; +  template <> +  struct GRStateTrait<CFErrorOut> : public GRStatePartialTrait<ErrorOutFlag> {   +    static void *GDMIndex() { static int index = 0; return &index; } +  }; +}  } -void -NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, -                             llvm::SmallVectorImpl<VarDecl*>& ErrorParams) { +template <typename T> +static bool hasFlag(SVal val, const GRState *state) { +  if (SymbolRef sym = val.getAsSymbol()) +    if (const unsigned *attachedFlags = state->get<T>(sym)) +      return *attachedFlags; +  return false; +} -  ResultTy = M.getResultType(); +template <typename T> +static void setFlag(const GRState *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)); +} -  for (ObjCMethodDecl::param_iterator I=M.param_begin(), -       E=M.param_end(); I!=E; ++I)  { +void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad, +                                            CheckerContext &C) const { +  if (!isLoad) +    return; +  if (loc.isUndef() || !isa<Loc>(loc)) +    return; -    QualType T = (*I)->getType(); +  const GRState *state = C.getState(); + +  // If we are loading from NSError**/CFErrorRef* parameter, mark the resulting +  // SVal so that we can later check it when handling the +  // ImplicitNullDerefEvent event. +  // FIXME: Cumbersome! Maybe add hook at construction of SVals at start of +  // function ? +   +  const VarDecl *VD = loc.getAsVarDecl(); +  if (!VD) return; +  const ParmVarDecl *PD = dyn_cast<ParmVarDecl>(VD); +  if (!PD) return; + +  if (!NSErrorII) +    NSErrorII = &PD->getASTContext().Idents.get("NSError"); +  if (!CFErrorII) +    CFErrorII = &PD->getASTContext().Idents.get("CFErrorRef"); + +  if (ShouldCheckNSError && IsNSError(PD, NSErrorII)) { +    setFlag<NSErrorOut>(state, state->getSVal(cast<Loc>(loc)), C); +    return; +  } -    if (isNSErrorWarning) { -      if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I); -    } -    else if (CheckCFErrorArgument(T)) -      ErrorParams.push_back(*I); +  if (ShouldCheckCFError && IsCFError(PD, CFErrorII)) { +    setFlag<CFErrorOut>(state, state->getSVal(cast<Loc>(loc)), C); +    return;    }  } -void -NSErrorChecker::CheckSignature(const FunctionDecl& F, QualType& ResultTy, -                             llvm::SmallVectorImpl<VarDecl*>& ErrorParams) { +void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const { +  if (event.IsLoad) +    return; -  ResultTy = F.getResultType(); +  SVal loc = event.Location; +  const GRState *state = event.SinkNode->getState(); +  BugReporter &BR = *event.BR; -  for (FunctionDecl::param_const_iterator I = F.param_begin(), -                                          E = F.param_end(); I != E; ++I)  { +  bool isNSError = hasFlag<NSErrorOut>(loc, state); +  bool isCFError = false; +  if (!isNSError) +    isCFError = hasFlag<CFErrorOut>(loc, state); -    QualType T = (*I)->getType(); +  if (!(isNSError || isCFError)) +    return; -    if (isNSErrorWarning) { -      if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I); -    } -    else if (CheckCFErrorArgument(T)) -      ErrorParams.push_back(*I); -  } -} +  // Storing to possible null NSError/CFErrorRef out parameter. + +  // Emit an error. +  std::string err; +  llvm::raw_string_ostream os(err); +    os << "Potential null dereference.  According to coding standards "; + +  if (isNSError) +    os << "in 'Creating and Returning NSError Objects' the parameter '"; +  else +    os << "documented in CoreFoundation/CFError.h the parameter '"; +  os  << "' may be null."; -bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) { +  BugType *bug = 0; +  if (isNSError) +    bug = new NSErrorDerefBug(); +  else +    bug = new CFErrorDerefBug(); +  EnhancedBugReport *report = new EnhancedBugReport(*bug, os.str(), +                                                    event.SinkNode); +  BR.EmitReport(report); +} + +static bool IsNSError(const ParmVarDecl *PD, IdentifierInfo *II) { -  const PointerType* PPT = ArgTy->getAs<PointerType>(); +  const PointerType* PPT = PD->getType()->getAs<PointerType>();    if (!PPT)      return false; @@ -181,9 +288,8 @@ bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) {    return false;  } -bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) { - -  const PointerType* PPT = ArgTy->getAs<PointerType>(); +static bool IsCFError(const ParmVarDecl *PD, IdentifierInfo *II) { +  const PointerType* PPT = PD->getType()->getAs<PointerType>();    if (!PPT) return false;    const TypedefType* TT = PPT->getPointeeType()->getAs<TypedefType>(); @@ -192,47 +298,16 @@ bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) {    return TT->getDecl()->getIdentifier() == II;  } -void NSErrorChecker::CheckParamDeref(const VarDecl *Param, -                                   const LocationContext *LC, -                                   const GRState *rootState, -                                   BugReporter& BR) { - -  SVal ParamL = rootState->getLValue(Param, LC); -  const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>(); -  assert (ParamR && "Parameters always have VarRegions."); -  SVal ParamSVal = rootState->getSVal(ParamR); - -  // FIXME: For now assume that ParamSVal is symbolic.  We need to generalize -  // this later. -  SymbolRef ParamSym = ParamSVal.getAsLocSymbol(); -  if (!ParamSym) -    return; +void ento::registerNSErrorChecker(CheckerManager &mgr) { +  mgr.registerChecker<NSErrorMethodChecker>(); +  NSOrCFErrorDerefChecker * +    checker = mgr.registerChecker<NSOrCFErrorDerefChecker>(); +  checker->ShouldCheckNSError = true; +} -  // Iterate over the implicit-null dereferences. -  ExplodedNode *const* I,  *const* E; -  llvm::tie(I, E) = GetImplicitNullDereferences(Eng); -  for ( ; I != E; ++I) { -    const GRState *state = (*I)->getState(); -    SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt()); -    if (location.getAsSymbol() != ParamSym) -      continue; - -    // Emit an error. -    std::string sbuf; -    llvm::raw_string_ostream os(sbuf); -      os << "Potential null dereference.  According to coding standards "; - -    if (isNSErrorWarning) -      os << "in 'Creating and Returning NSError Objects' the parameter '"; -    else -      os << "documented in CoreFoundation/CFError.h the parameter '"; - -    os << Param << "' may be null."; - -    BugReport *report = new BugReport(*this, os.str(), *I); -    // FIXME: Notable symbols are now part of the report.  We should -    //  add support for notable symbols in BugReport. -    //    BR.addNotableSymbol(SV->getSymbol()); -    BR.EmitReport(report); -  } +void ento::registerCFErrorChecker(CheckerManager &mgr) { +  mgr.registerChecker<CFErrorFunctionChecker>(); +  NSOrCFErrorDerefChecker * +    checker = mgr.registerChecker<NSOrCFErrorDerefChecker>(); +  checker->ShouldCheckCFError = true;  } diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index cc5fb6a599d..787d38d4c99 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -339,8 +339,6 @@ static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,      return;    ExprEngine Eng(mgr, TF.take()); -  RegisterNSErrorChecks(Eng.getBugReporter(), Eng, *D); -    // Set the graph auditor.    llvm::OwningPtr<ExplodedNode::Auditor> Auditor;    if (mgr.shouldVisualizeUbigraph()) { diff --git a/clang/test/Analysis/CheckNSError.m b/clang/test/Analysis/CheckNSError.m index d12ad4eb2e6..9265972209b 100644 --- a/clang/test/Analysis/CheckNSError.m +++ b/clang/test/Analysis/CheckNSError.m @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,cocoa.NSError,macosx.CFError -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,cocoa.NSError,macosx.CFError -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,cocoa.NSError,macosx.CFError -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,cocoa.NSError,macosx.CFError -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s  typedef signed char BOOL; diff --git a/clang/test/Analysis/bstring.c b/clang/test/Analysis/bstring.c index ff73d745be5..ec2cc86a685 100644 --- a/clang/test/Analysis/bstring.c +++ b/clang/test/Analysis/bstring.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -verify %s  //===----------------------------------------------------------------------===  // Declarations diff --git a/clang/test/Analysis/complex.c b/clang/test/Analysis/complex.c index c8bdce01536..a0980ec0d25 100644 --- a/clang/test/Analysis/complex.c +++ b/clang/test/Analysis/complex.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s  #include <stdint.h> diff --git a/clang/test/Analysis/constant-folding.c b/clang/test/Analysis/constant-folding.c index 5eea2519c7d..4181e8afa66 100644 --- a/clang/test/Analysis/constant-folding.c +++ b/clang/test/Analysis/constant-folding.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.UnreachableCode -analyzer-check-objc-mem -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.UnreachableCode -analyzer-check-objc-mem -verify %s  // Trigger a warning if the analyzer reaches this point in the control flow.  #define WARN ((void)*(char*)0) diff --git a/clang/test/Analysis/dtor.cpp b/clang/test/Analysis/dtor.cpp index ea5b04684d7..f6b7138a70c 100644 --- a/clang/test/Analysis/dtor.cpp +++ b/clang/test/Analysis/dtor.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -analyzer-inline-call -cfg-add-implicit-dtors -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store region -analyzer-inline-call -cfg-add-implicit-dtors -verify %s  class A {  public: diff --git a/clang/test/Analysis/flat-store.c b/clang/test/Analysis/flat-store.c index bb274b0d5df..fc739df5fc9 100644 --- a/clang/test/Analysis/flat-store.c +++ b/clang/test/Analysis/flat-store.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=flat -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store=flat -verify %s  #define FAIL ((void)*(char*)0)  struct simple { int x; }; diff --git a/clang/test/Analysis/idempotent-operations-limited-loops.c b/clang/test/Analysis/idempotent-operations-limited-loops.c index e4c34cdead3..807280fa057 100644 --- a/clang/test/Analysis/idempotent-operations-limited-loops.c +++ b/clang/test/Analysis/idempotent-operations-limited-loops.c @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps -analyzer-max-loop 3 -verify %s -// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps -analyzer-max-loop 4 -verify %s -// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps %s -verify +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core,core.experimental.IdempotentOps -analyzer-max-loop 3 -verify %s +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core,core.experimental.IdempotentOps -analyzer-max-loop 4 -verify %s +// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core,core.experimental.IdempotentOps %s -verify  void always_warning() { int *p = 0; *p = 0xDEADBEEF; } // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} diff --git a/clang/test/Analysis/inline.c b/clang/test/Analysis/inline.c index d7a599a7654..aee821bd54f 100644 --- a/clang/test/Analysis/inline.c +++ b/clang/test/Analysis/inline.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s  int test1_f1() {    int y = 1; diff --git a/clang/test/Analysis/misc-ps-basic-store.m b/clang/test/Analysis/misc-ps-basic-store.m index 55042c14258..cf235a99a8a 100644 --- a/clang/test/Analysis/misc-ps-basic-store.m +++ b/clang/test/Analysis/misc-ps-basic-store.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify -fblocks %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify -fblocks %s  //---------------------------------------------------------------------------  // Test case 'checkaccess_union' differs for region store and basic store. diff --git a/clang/test/Analysis/misc-ps-region-store.cpp b/clang/test/Analysis/misc-ps-region-store.cpp index 7c296fd3db9..c6206bf19f2 100644 --- a/clang/test/Analysis/misc-ps-region-store.cpp +++ b/clang/test/Analysis/misc-ps-region-store.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks   -analyzer-opt-analyze-nested-blocks %s +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks   -analyzer-opt-analyze-nested-blocks %s  // Test basic handling of references.  char &test1_aux(); diff --git a/clang/test/Analysis/override-werror.c b/clang/test/Analysis/override-werror.c index ce0f1ac9abe..4b812295fd8 100644 --- a/clang/test/Analysis/override-werror.c +++ b/clang/test/Analysis/override-werror.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -Werror %s -analyzer-store=basic -verify -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -Werror %s -analyzer-store=region -verify +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -Werror %s -analyzer-store=basic -verify +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -Werror %s -analyzer-store=region -verify  // This test case illustrates that using '-analyze' overrides the effect of  // -Werror.  This allows basic warnings not to interfere with producing diff --git a/clang/test/Analysis/plist-output-alternate.m b/clang/test/Analysis/plist-output-alternate.m index 7b8c2673b08..e22fd2d7f94 100644 --- a/clang/test/Analysis/plist-output-alternate.m +++ b/clang/test/Analysis/plist-output-alternate.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s  void test_null_init(void) {    int *p = 0; diff --git a/clang/test/Analysis/retain-release-region-store.m b/clang/test/Analysis/retain-release-region-store.m index ec765e3fe80..4279bcfc552 100644 --- a/clang/test/Analysis/retain-release-region-store.m +++ b/clang/test/Analysis/retain-release-region-store.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-max-loop 6 -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store=region -analyzer-max-loop 6 -verify %s  //===----------------------------------------------------------------------===//  // The following code is reduced using delta-debugging from diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c index 756115180ca..967fe4d5159 100644 --- a/clang/test/Analysis/string.c +++ b/clang/test/Analysis/string.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s  //===----------------------------------------------------------------------===  // Declarations diff --git a/clang/test/Analysis/unreachable-code-path.c b/clang/test/Analysis/unreachable-code-path.c index 34763e63b98..322611aa139 100644 --- a/clang/test/Analysis/unreachable-code-path.c +++ b/clang/test/Analysis/unreachable-code-path.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=DeadStores,core.experimental.UnreachableCode -analyzer-check-objc-mem -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,DeadStores,core.experimental.UnreachableCode -analyzer-check-objc-mem -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s  extern void foo(int a); diff --git a/clang/test/Coverage/html-diagnostics.c b/clang/test/Coverage/html-diagnostics.c index be820fb90f2..0b1580e8864 100644 --- a/clang/test/Coverage/html-diagnostics.c +++ b/clang/test/Coverage/html-diagnostics.c @@ -1,5 +1,5 @@  // RUN: rm -rf %t -// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-check-objc-mem -o %t %s +// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -analyzer-check-objc-mem -o %t %s  // RUN: cat %t/*.html | FileCheck %s  // CHECK: <h3>Annotated Source Code</h3>  | 

