From be879727893994532b4a643bfae6fb656742057f Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Thu, 13 Sep 2012 18:18:37 +0000 Subject: [PATCH] When warning about unsafe uses of dispatch_once, specially handle the 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163816 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | 14 +++++++++++++- test/Analysis/unix-fns.c | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index cfdb55df73..97bb80c9e1 100644 --- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -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(Name) - .Cases("dispatch_once", "dispatch_once_f", + .Cases("dispatch_once", + "_dispatch_once", + "dispatch_once_f", &MacOSXAPIChecker::CheckDispatchOnce) .Default(NULL); diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c index ec620985d9..f9c052e165 100644 --- a/test/Analysis/unix-fns.c +++ b/test/Analysis/unix-fns.c @@ -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}} +} -- 2.50.1