Index: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -79,7 +79,9 @@ mutable IdentifierInfo *II = nullptr; mutable bool IsLookupDone = false; - StringRef FuncName; + // The list of the function name, include the qualifiers, used to identify the + // specified CallEvent, e.g. "{a, b, X}" represent the method call of "a::b::X". + std::vector QualifiedName; unsigned RequiredArgs; public: @@ -87,16 +89,22 @@ /// Constructs a CallDescription object. /// - /// @param FuncName The name of the function that will be matched. + /// @param QualifiedName The list of the qualified name of the function that + /// will be matched. It does not require the user to provide the full list of + /// the qualified name. The more details provided, the more accurate the + /// matching. /// /// @param RequiredArgs The number of arguments that is expected to match a /// call. Omit this parameter to match every occurrence of call with a given /// name regardless the number of arguments. - CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement) - : FuncName(FuncName), RequiredArgs(RequiredArgs) {} + CallDescription(std::vector QualifiedName, + unsigned RequiredArgs = NoArgRequirement) + : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {} /// Get the name of the function that this object matches. - StringRef getFunctionName() const { return FuncName; } + StringRef getFunctionName() const { + return QualifiedName.back(); + } }; template Index: lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp +++ lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp @@ -65,15 +65,15 @@ BlockInCriticalSectionChecker::BlockInCriticalSectionChecker() : IILockGuard(nullptr), IIUniqueLock(nullptr), - LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"), - FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"), - PthreadLockFn("pthread_mutex_lock"), - PthreadTryLockFn("pthread_mutex_trylock"), - PthreadUnlockFn("pthread_mutex_unlock"), - MtxLock("mtx_lock"), - MtxTimedLock("mtx_timedlock"), - MtxTryLock("mtx_trylock"), - MtxUnlock("mtx_unlock"), + LockFn({"lock"}), UnlockFn({"unlock"}), SleepFn({"sleep"}), GetcFn({"getc"}), + FgetsFn({"fgets"}), ReadFn({"read"}), RecvFn({"recv"}), + PthreadLockFn({"pthread_mutex_lock"}), + PthreadTryLockFn({"pthread_mutex_trylock"}), + PthreadUnlockFn({"pthread_mutex_unlock"}), + MtxLock({"mtx_lock"}), + MtxTimedLock({"mtx_timedlock"}), + MtxTryLock({"mtx_trylock"}), + MtxUnlock({"mtx_unlock"}), ClassLockGuard("lock_guard"), ClassUniqueLock("unique_lock"), IdentifierInfoInitialized(false) { Index: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp +++ lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp @@ -31,7 +31,7 @@ CallDescription CStrFn; public: - DanglingInternalBufferChecker() : CStrFn("c_str") {} + DanglingInternalBufferChecker() : CStrFn({"std", "basic_string", "c_str"}) {} /// Record the connection between the symbol returned by c_str() and the /// corresponding string object region in the ProgramState. Mark the symbol @@ -59,10 +59,6 @@ if (!TypedR) return; - auto *TypeDecl = TypedR->getValueType()->getAsCXXRecordDecl(); - if (TypeDecl->getName() != "basic_string") - return; - ProgramStateRef State = C.getState(); if (Call.isCalled(CStrFn)) { Index: lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp +++ lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp @@ -34,7 +34,7 @@ static int ProtRead; mutable std::unique_ptr BT; public: - MmapWriteExecChecker() : MmapFn("mmap", 6), MprotectFn("mprotect", 3) {} + MmapWriteExecChecker() : MmapFn({"mmap"}, 6), MprotectFn({"mprotect"}, 3) {} void checkPreCall(const CallEvent &Call, CheckerContext &C) const; int ProtExecOv; int ProtReadOv; Index: lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -104,7 +104,7 @@ } // end anonymous namespace SimpleStreamChecker::SimpleStreamChecker() - : OpenFn("fopen"), CloseFn("fclose", 1) { + : OpenFn({"fopen"}), CloseFn({"fclose"}, 1) { // Initialize the bug types. DoubleCloseBugType.reset( new BugType(this, "Double fclose", "Unix Stream API Error")); Index: lib/StaticAnalyzer/Checkers/ValistChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/ValistChecker.cpp +++ lib/StaticAnalyzer/Checkers/ValistChecker.cpp @@ -103,24 +103,24 @@ const SmallVector ValistChecker::VAListAccepters = { - {{"vfprintf", 3}, 2}, - {{"vfscanf", 3}, 2}, - {{"vprintf", 2}, 1}, - {{"vscanf", 2}, 1}, - {{"vsnprintf", 4}, 3}, - {{"vsprintf", 3}, 2}, - {{"vsscanf", 3}, 2}, - {{"vfwprintf", 3}, 2}, - {{"vfwscanf", 3}, 2}, - {{"vwprintf", 2}, 1}, - {{"vwscanf", 2}, 1}, - {{"vswprintf", 4}, 3}, + {{{"vfprintf"}, 3}, 2}, + {{{"vfscanf"}, 3}, 2}, + {{{"vprintf"}, 2}, 1}, + {{{"vscanf"}, 2}, 1}, + {{{"vsnprintf"}, 4}, 3}, + {{{"vsprintf"}, 3}, 2}, + {{{"vsscanf"}, 3}, 2}, + {{{"vfwprintf"}, 3}, 2}, + {{{"vfwscanf"}, 3}, 2}, + {{{"vwprintf"}, 2}, 1}, + {{{"vwscanf"}, 2}, 1}, + {{{"vswprintf"}, 4}, 3}, // vswprintf is the wide version of vsnprintf, // vsprintf has no wide version - {{"vswscanf", 3}, 2}}; -const CallDescription ValistChecker::VaStart("__builtin_va_start", 2), - ValistChecker::VaCopy("__builtin_va_copy", 2), - ValistChecker::VaEnd("__builtin_va_end", 1); + {{{"vswscanf"}, 3}, 2}}; +const CallDescription ValistChecker::VaStart({"__builtin_va_start"}, 2), + ValistChecker::VaCopy({"__builtin_va_copy"}, 2), + ValistChecker::VaEnd({"__builtin_va_end"}, 1); } // end anonymous namespace void ValistChecker::checkPreCall(const CallEvent &Call, Index: lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- lib/StaticAnalyzer/Core/CallEvent.cpp +++ lib/StaticAnalyzer/Core/CallEvent.cpp @@ -28,6 +28,7 @@ #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/ProgramPoint.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" @@ -65,6 +66,7 @@ using namespace clang; using namespace ento; +using namespace clang::ast_matchers; QualType CallEvent::getResultType() const { ASTContext &Ctx = getState()->getStateManager().getContext(); @@ -256,11 +258,28 @@ return false; if (!CD.IsLookupDone) { CD.IsLookupDone = true; - CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName); + CD.II = &getState()->getStateManager().getContext().Idents.get( + CD.getFunctionName()); } const IdentifierInfo *II = getCalleeIdentifier(); if (!II || II != CD.II) return false; + + if (CD.QualifiedName.size() > 1) { + const NamedDecl *ND = dyn_cast_or_null(getDecl()); + if (!ND) + return false; + + std::string Regex = "^::(.*)?"; + Regex += llvm::join(CD.QualifiedName, "(.*)?::(.*)?") + "(.*)?$"; + + auto Matches = match(namedDecl(matchesName(Regex)).bind("Regex"), *ND, + LCtx->getAnalysisDeclContext()->getASTContext()); + + if (Matches.empty()) + return false; + } + return (CD.RequiredArgs == CallDescription::NoArgRequirement || CD.RequiredArgs == getNumArgs()); }