diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp | 110 | 
1 files changed, 40 insertions, 70 deletions
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 48d7c367a96d..0ecc391f3e8f 100644 --- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -28,26 +28,18 @@ using llvm::Optional;  namespace {  class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > { -  enum SubChecks { -    OpenFn = 0, -    PthreadOnceFn = 1, -    MallocZero = 2, -    NumChecks -  }; - -  mutable BugType *BTypes[NumChecks]; - -public: +  mutable llvm::OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;    mutable Optional<uint64_t> Val_O_CREAT;  public: -  UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } -  ~UnixAPIChecker() { -    for (unsigned i=0; i != NumChecks; ++i) -      delete BTypes[i]; -  } -    void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + +  void CheckOpen(CheckerContext &C, const CallExpr *CE) const; +  void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const; +  void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const; + +  typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &, +                                             const CallExpr *) const;  };  } //end anonymous namespace @@ -55,23 +47,23 @@ public:  // Utility functions.  //===----------------------------------------------------------------------===// -static inline void LazyInitialize(BugType *&BT, const char *name) { +static inline void LazyInitialize(llvm::OwningPtr<BugType> &BT, +                                  const char *name) {    if (BT)      return; -  BT = new BugType(name, "Unix API"); +  BT.reset(new BugType(name, "Unix API"));  }  //===----------------------------------------------------------------------===//  // "open" (man 2 open)  //===----------------------------------------------------------------------===// -static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC, -                      const CallExpr *CE, BugType *&BT) { +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 (!UC.Val_O_CREAT.hasValue()) { +  if (!Val_O_CREAT.hasValue()) {      if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple) -      UC.Val_O_CREAT = 0x0200; +      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 @@ -80,8 +72,6 @@ static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,      }    } -  LazyInitialize(BT, "Improper use of 'open'"); -    // Look at the 'oflags' argument for the O_CREAT flag.    const GRState *state = C.getState(); @@ -101,7 +91,7 @@ static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,    }    NonLoc oflags = cast<NonLoc>(V);    NonLoc ocreateFlag = -    cast<NonLoc>(C.getSValBuilder().makeIntVal(UC.Val_O_CREAT.getValue(), +    cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(),                                                  oflagsEx->getType()));    SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,                                                        oflags, ocreateFlag, @@ -124,8 +114,10 @@ static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,      if (!N)        return; -    EnhancedBugReport *report = -      new EnhancedBugReport(*BT, +    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()); @@ -137,14 +129,12 @@ static void CheckOpen(CheckerContext &C, const UnixAPIChecker &UC,  // pthread_once  //===----------------------------------------------------------------------===// -static void CheckPthreadOnce(CheckerContext &C, const UnixAPIChecker &, -                             const CallExpr *CE, BugType *&BT) { +void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C, +                                      const CallExpr *CE) const {    // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.    // They can possibly be refactored. -  LazyInitialize(BT, "Improper use of 'pthread_once'"); -    if (CE->getNumArgs() < 1)      return; @@ -171,7 +161,9 @@ static void CheckPthreadOnce(CheckerContext &C, const UnixAPIChecker &,    if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))      os << "  Perhaps you intended to declare the variable as 'static'?"; -  EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); +  LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'"); + +  RangedBugReport *report = new RangedBugReport(*BT_pthreadOnce, os.str(), N);    report->addRange(CE->getArg(0)->getSourceRange());    C.EmitReport(report);  } @@ -182,8 +174,8 @@ static void CheckPthreadOnce(CheckerContext &C, const UnixAPIChecker &,  // FIXME: Eventually this should be rolled into the MallocChecker, but this  // check is more basic and is valuable for widespread use. -static void CheckMallocZero(CheckerContext &C, const UnixAPIChecker &UC, -                            const CallExpr *CE, BugType *&BT) { +void UnixAPIChecker::CheckMallocZero(CheckerContext &C, +                                     const CallExpr *CE) const {    // Sanity check that malloc takes one argument.    if (CE->getNumArgs() != 1) @@ -208,11 +200,11 @@ static void CheckMallocZero(CheckerContext &C, const UnixAPIChecker &UC,      // FIXME: Add reference to CERT advisory, and/or C99 standard in bug      // output. -    LazyInitialize(BT, "Undefined allocation of 0 bytes"); +    LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");      EnhancedBugReport *report = -      new EnhancedBugReport(*BT, "Call to 'malloc' has an allocation size" -                                 " of 0 bytes", N); +      new EnhancedBugReport(*BT_mallocZero, "Call to 'malloc' has an allocation" +                                            " size of 0 bytes", N);      report->addRange(CE->getArg(0)->getSourceRange());      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,                                CE->getArg(0)); @@ -230,51 +222,29 @@ static void CheckMallocZero(CheckerContext &C, const UnixAPIChecker &UC,  // Central dispatch function.  //===----------------------------------------------------------------------===// -typedef void (*SubChecker)(CheckerContext &C, const UnixAPIChecker &UC, -                           const CallExpr *CE, BugType *&BT); -namespace { -  class SubCheck { -    SubChecker SC; -    const UnixAPIChecker *UC; -    BugType **BT; -  public: -    SubCheck(SubChecker sc, const UnixAPIChecker *uc, BugType *& bt) -      : SC(sc), UC(uc), BT(&bt) {} -    SubCheck() : SC(NULL), UC(NULL), BT(NULL) {} - -    void run(CheckerContext &C, const CallExpr *CE) const { -      if (SC) -        SC(C, *UC, CE, *BT); -    } -  }; -} // end anonymous namespace -  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 FunctionTextRegion *Fn = -    dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion()); +  const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();    if (!Fn)      return; -  const IdentifierInfo *FI = Fn->getDecl()->getIdentifier(); +  const IdentifierInfo *FI = Fn->getIdentifier();    if (!FI)      return; -  const SubCheck &SC = -    llvm::StringSwitch<SubCheck>(FI->getName()) -      .Case("open", -            SubCheck(CheckOpen, this, BTypes[OpenFn])) -      .Case("pthread_once", -            SubCheck(CheckPthreadOnce, this, BTypes[PthreadOnceFn])) -      .Case("malloc", -            SubCheck(CheckMallocZero, this, BTypes[MallocZero])) -      .Default(SubCheck()); - -  SC.run(C, CE); +  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);  }  //===----------------------------------------------------------------------===//  | 
