[cfe-commits] r97116 - in /cfe/trunk/lib/Checker: CMakeLists.txt GRExprEngine.cpp GRExprEngineInternalChecks.h MacOSXAPIChecker.cpp

Ted Kremenek kremenek at apple.com
Wed Feb 24 21:44:09 PST 2010


Author: kremenek
Date: Wed Feb 24 23:44:09 2010
New Revision: 97116

URL: http://llvm.org/viewvc/llvm-project?rev=97116&view=rev
Log:
Add MacOSXAPIChecker, a meta checker to include various precondition checks for calls
to various MacOS X functions.  The checks in BasicObjCFoundationChecks.cpp will
gradually be migrated here.

As a first check, check that when 'dispatch_once()' is passed a predicate value
that has non-local storage.

Added:
    cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp
Modified:
    cfe/trunk/lib/Checker/CMakeLists.txt
    cfe/trunk/lib/Checker/GRExprEngine.cpp
    cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h

Modified: cfe/trunk/lib/Checker/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CMakeLists.txt?rev=97116&r1=97115&r2=97116&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/CMakeLists.txt (original)
+++ cfe/trunk/lib/Checker/CMakeLists.txt Wed Feb 24 23:44:09 2010
@@ -34,6 +34,7 @@
   GRExprEngineExperimentalChecks.cpp
   GRState.cpp
   LLVMConventionsChecker.cpp
+  MacOSXAPIChecker.cpp
   MallocChecker.cpp
   ManagerRegistry.cpp
   MemRegion.cpp

Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97116&r1=97115&r2=97116&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Checker/GRExprEngine.cpp Wed Feb 24 23:44:09 2010
@@ -319,6 +319,7 @@
   RegisterBuiltinFunctionChecker(Eng);
   RegisterOSAtomicChecker(Eng);
   RegisterUnixAPIChecker(Eng);
+  RegisterMacOSXAPIChecker(Eng);
 }
 
 GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)

Modified: cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h?rev=97116&r1=97115&r2=97116&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h (original)
+++ cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Wed Feb 24 23:44:09 2010
@@ -43,6 +43,7 @@
 void RegisterVLASizeChecker(GRExprEngine &Eng);
 
 // API checks.
+void RegisterMacOSXAPIChecker(GRExprEngine &Eng);
 void RegisterOSAtomicChecker(GRExprEngine &Eng);
 void RegisterUnixAPIChecker(GRExprEngine &Eng);
 

Added: cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp?rev=97116&view=auto
==============================================================================
--- cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp (added)
+++ cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp Wed Feb 24 23:44:09 2010
@@ -0,0 +1,141 @@
+// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines MacOSXAPIChecker, which is an assortment of checks on calls
+// to various, widely used Mac OS X functions.
+//
+// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
+// to here, using the new Checker interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace {
+class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
+  enum SubChecks {
+    DispatchOnce = 0,
+    DispatchOnceF,
+    NumChecks
+  };
+
+  BugType *BTypes[NumChecks];
+
+public:
+  MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
+  static void *getTag() { static unsigned tag = 0; return &tag; }
+
+  void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} //end anonymous namespace
+
+void clang::RegisterMacOSXAPIChecker(GRExprEngine &Eng) {
+  if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
+    Eng.registerCheck(new MacOSXAPIChecker());
+}
+
+//===----------------------------------------------------------------------===//
+// dispatch_once and dispatch_once_f
+//===----------------------------------------------------------------------===//
+
+static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
+                              BugType *&BT, const IdentifierInfo *FI) {
+
+  if (!BT) {
+    llvm::SmallString<128> S;
+    llvm::raw_svector_ostream os(S);
+    os << "Improper use of '" << FI->getName() << '\'';
+    BT = new BugType(os.str(), "Mac OS X API");
+  }
+
+  if (CE->getNumArgs() < 1)
+    return;
+
+  // Check if the first argument is stack allocated.  If so, issue a warning
+  // because that's likely to be bad news.
+  const GRState *state = C.getState();
+  const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+    return;
+
+  ExplodedNode *N = C.GenerateSink(state);
+  if (!N)
+    return;
+
+  llvm::SmallString<256> S;
+  llvm::raw_svector_ostream os(S);
+  os << "Call to '" << FI->getName() << "' uses";
+  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+    os << " the local variable '" << VR->getDecl()->getName() << '\'';
+  else
+    os << " stack allocated memory";
+  os << " for the predicate value.  Using such transient memory for "
+        "the predicate is potentially dangerous.";
+  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);
+  report->addRange(CE->getArg(0)->getSourceRange());
+  C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
+// Central dispatch function.
+//===----------------------------------------------------------------------===//
+
+typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
+                           const IdentifierInfo *FI);
+namespace {
+  class SubCheck {
+    SubChecker SC;
+    BugType **BT;
+  public:
+    SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
+    SubCheck() : SC(NULL), BT(NULL) {}
+
+    void run(CheckerContext &C, const CallExpr *CE,
+             const IdentifierInfo *FI) const {
+      if (SC)
+        SC(C, CE, *BT, FI);
+    }
+  };
+} // end anonymous namespace
+
+void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+  // FIXME: Mostly copy and paste from UnixAPIChecker.  Should refactor.
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  const FunctionTextRegion *Fn =
+    dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
+
+  if (!Fn)
+    return;
+
+  const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
+  if (!FI)
+    return;
+
+  const SubCheck &SC =
+    llvm::StringSwitch<SubCheck>(FI->getName())
+      .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
+      .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
+                                        BTypes[DispatchOnceF]))
+      .Default(SubCheck());
+
+  SC.run(C, CE, FI);
+}





More information about the cfe-commits mailing list