]> granicus.if.org Git - clang/commitdiff
When warning about unsafe uses of dispatch_once, specially handle the
authorTed Kremenek <kremenek@apple.com>
Thu, 13 Sep 2012 18:18:37 +0000 (18:18 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 13 Sep 2012 18:18:37 +0000 (18:18 +0000)
crazy case where dispatch_once gets redefined as a macro that calls
_dispatch_once (which calls the real dispatch_once).  Users want to
see the warning in their own code.

Fixes <rdar://problem/11617767>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163816 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
test/Analysis/unix-fns.c

index cfdb55df730d9831b3e3668234002159e564f8a8..97bb80c9e19a17e4c692acdfbb8cd1915b653d66 100644 (file)
@@ -70,6 +70,16 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
     BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'",
                                       "Mac OS X API"));
 
+  // Handle _dispatch_once, which in some versions of the OS X SDK that
+  // dispatch_once is a macro that wraps a call to _dispatch_once, which
+  // then calls the real dispatch_once.  Users do not care; they just
+  // want the warning at the top-level call.
+  if (CE->getLocStart().isMacroID()) {
+    StringRef TrimmedFName = FName.ltrim("_");
+    if (TrimmedFName != FName)
+      FName = TrimmedFName;
+  }
+  
   SmallString<256> S;
   llvm::raw_svector_ostream os(S);
   os << "Call to '" << FName << "' uses";
@@ -99,7 +109,9 @@ void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
 
   SubChecker SC =
     llvm::StringSwitch<SubChecker>(Name)
-      .Cases("dispatch_once", "dispatch_once_f",
+      .Cases("dispatch_once",
+             "_dispatch_once",
+             "dispatch_once_f",
              &MacOSXAPIChecker::CheckDispatchOnce)
       .Default(NULL);
 
index ec620985d95a3ef01c5982d47801faba81c7019b..f9c052e1654339b7ae66007a41cedcd7c2a2378d 100644 (file)
@@ -136,3 +136,18 @@ void test_valloc_nowarn(size_t sz) {
     foo[i] = 0;
   }
 }
+
+// Test dispatch_once being a macro that wraps a call to _dispatch_once, which in turn
+// calls the real dispatch_once.
+
+static inline void _dispatch_once(dispatch_once_t *predicate, dispatch_block_t block)
+{
+  dispatch_once(predicate, block);
+}
+
+#define dispatch_once _dispatch_once
+
+void test_dispatch_once_in_macro() {
+  dispatch_once_t pred = 0;
+  dispatch_once(&pred, ^(){});  // expected-warning {{Call to 'dispatch_once' uses the local variable 'pred' for the predicate value}}
+}