[cfe-commits] r100803 - in /cfe/trunk: lib/Checker/UnixAPIChecker.cpp test/Analysis/unix-fns.c

Ted Kremenek kremenek at apple.com
Thu Apr 8 12:53:31 PDT 2010


Author: kremenek
Date: Thu Apr  8 14:53:31 2010
New Revision: 100803

URL: http://llvm.org/viewvc/llvm-project?rev=100803&view=rev
Log:
Add static analyzer check for calls to 'pthread_once()' where the control-flow has
automatic storage.  This matches the corresponding check for 'dispatch_once()'.

Modified:
    cfe/trunk/lib/Checker/UnixAPIChecker.cpp
    cfe/trunk/test/Analysis/unix-fns.c

Modified: cfe/trunk/lib/Checker/UnixAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/UnixAPIChecker.cpp?rev=100803&r1=100802&r2=100803&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/UnixAPIChecker.cpp (original)
+++ cfe/trunk/lib/Checker/UnixAPIChecker.cpp Thu Apr  8 14:53:31 2010
@@ -24,6 +24,7 @@
 class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
   enum SubChecks {
     OpenFn = 0,
+    PthreadOnceFn = 1,
     NumChecks
   };
 
@@ -110,6 +111,49 @@
 }
 
 //===----------------------------------------------------------------------===//
+// pthread_once
+//===----------------------------------------------------------------------===//
+
+static void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE,
+                             BugType *&BT) {
+
+  // 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;
+
+  // 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 'pthread_once' uses";
+  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+    os << " the local variable '" << VR->getDecl()->getName() << '\'';
+  else
+    os << " stack allocated memory";
+  os << " for the \"control\" value.  Using such transient memory for "
+  "the control value 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.
 //===----------------------------------------------------------------------===//
 
@@ -147,6 +191,7 @@
   const SubCheck &SC =
     llvm::StringSwitch<SubCheck>(FI->getName())
       .Case("open", SubCheck(CheckOpen, BTypes[OpenFn]))
+      .Case("pthread_once", SubCheck(CheckPthreadOnce, BTypes[PthreadOnceFn]))
       .Default(SubCheck());
 
   SC.run(C, CE);

Modified: cfe/trunk/test/Analysis/unix-fns.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unix-fns.c?rev=100803&r1=100802&r2=100803&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/unix-fns.c (original)
+++ cfe/trunk/test/Analysis/unix-fns.c Thu Apr  8 14:53:31 2010
@@ -1,11 +1,24 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -analyzer-store=region
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -analyzer-store=basic
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem %s -analyzer-store=region -fblocks -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem %s -analyzer-store=basic -fblocks -verify
+
+struct _opaque_pthread_once_t {
+  long __sig;
+  char __opaque[8];
+};
+typedef struct _opaque_pthread_once_t    __darwin_pthread_once_t;
+typedef __darwin_pthread_once_t pthread_once_t;
+int pthread_once(pthread_once_t *, void (*)(void));
+
+typedef void (^dispatch_block_t)(void);
+typedef long dispatch_once_t;
+void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
 
 #ifndef O_CREAT
 #define O_CREAT 0x0200
 #define O_RDONLY 0x0000
 #endif
 int open(const char *, int, ...);
+int close(int fildes);
 
 void test_open(const char *path) {
   int fd;
@@ -17,3 +30,23 @@
   if (!fd)
     close(fd);
 } 
+
+void test_dispatch_once() {
+  dispatch_once_t pred = 0;
+  do { if (__builtin_expect(*(&pred), ~0l) != ~0l) dispatch_once((&pred), (^() {})); } while (0); // expected-warning{{Call to 'dispatch_once' uses the local variable 'pred' for the predicate value}}
+}
+void test_dispatch_once_neg() {
+  static dispatch_once_t pred = 0;
+  do { if (__builtin_expect(*(&pred), ~0l) != ~0l) dispatch_once((&pred), (^() {})); } while (0); // no-warning
+}
+
+void test_pthread_once_aux();
+
+void test_pthread_once() {
+  pthread_once_t pred = {0x30B1BCBA, {0}};
+  pthread_once(&pred, test_pthread_once_aux); // expected-warning{{Call to 'pthread_once' uses the local variable 'pred' for the "control" value}}
+}
+void test_pthread_once_neg() {
+  static pthread_once_t pred = {0x30B1BCBA, {0}};
+  pthread_once(&pred, test_pthread_once_aux); // no-warning
+}





More information about the cfe-commits mailing list