[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