MTC updated this revision to Diff 152702. MTC added a comment. Sorry for the long long delay, I was on the Dragon Boat Festival a few days ago.
This update has two parts: - Use the `matchesName` to match the AST node with the specified name, `matchesName` use regex to match the specified name. - Use `std::vector` to record the list of qualified name, user can provide information as much as possible to improve matching accuracy. But can also provide only the function name. There are two remain issues: - There is possible match the wrong AST node, e.g. for the NamedDecl `foo()`, if the function body has the `a::b::x`, when we match `a::b::X()`, we will match `foo()` . Because I'm not familiar with ASTMatcher, my bad, I can't think of a perfect way to match only the specified nodes. - The `std::vector` to record the information provide by the users may be not the best data structure. - I'm not the regex expert, the regex used in this patch definitely has the chance to improve. And I am not good at English writing, if any comments are not very clear, please correct me. Thanks for the help! Repository: rC Clang https://reviews.llvm.org/D48027 Files: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp lib/StaticAnalyzer/Checkers/ValistChecker.cpp lib/StaticAnalyzer/Core/CallEvent.cpp
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<NamedDecl>(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()); } Index: lib/StaticAnalyzer/Checkers/ValistChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/ValistChecker.cpp +++ lib/StaticAnalyzer/Checkers/ValistChecker.cpp @@ -103,24 +103,24 @@ const SmallVector<ValistChecker::VAListAccepter, 15> 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/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/MmapWriteExecChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp +++ lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp @@ -34,7 +34,7 @@ static int ProtRead; mutable std::unique_ptr<BugType> 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/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/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: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -79,24 +79,32 @@ 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<StringRef> QualifiedName; unsigned RequiredArgs; public: const static unsigned NoArgRequirement = std::numeric_limits<unsigned>::max(); /// 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<StringRef> 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<typename T = CallEvent>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits