================ @@ -20,48 +20,180 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" + +#include <iterator> +#include <utility> +#include <variant> using namespace clang; using namespace ento; namespace { + +struct CritSectionMarker { + const Expr *LockExpr{}; + const MemRegion *LockReg{}; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.Add(LockExpr); + ID.Add(LockReg); + } + + [[nodiscard]] constexpr bool + operator==(const CritSectionMarker &Other) const noexcept { + return LockExpr == Other.LockExpr && LockReg == Other.LockReg; + } + [[nodiscard]] constexpr bool + operator!=(const CritSectionMarker &Other) const noexcept { + return !(*this == Other); + } +}; + +class FirstArgMutexDescriptor { + CallDescription LockFn; + CallDescription UnlockFn; + +public: + FirstArgMutexDescriptor(CallDescription &&LockFn, CallDescription &&UnlockFn) + : LockFn(std::move(LockFn)), UnlockFn(std::move(UnlockFn)) {} + [[nodiscard]] bool matchesLock(const CallEvent &Call) const { + return LockFn.matches(Call) && Call.getNumArgs() > 0; + } + [[nodiscard]] bool matchesUnlock(const CallEvent &Call) const { + return UnlockFn.matches(Call) && Call.getNumArgs() > 0; + } + [[nodiscard]] const MemRegion *getLockRegion(const CallEvent &Call) const { + return Call.getArgSVal(0).getAsRegion(); + } + [[nodiscard]] const MemRegion *getUnlockRegion(const CallEvent &Call) const { + return Call.getArgSVal(0).getAsRegion(); + } +}; + +class MemberMutexDescriptor { + CallDescription LockFn; + CallDescription UnlockFn; + +public: + MemberMutexDescriptor(CallDescription &&LockFn, CallDescription &&UnlockFn) + : LockFn(std::move(LockFn)), UnlockFn(std::move(UnlockFn)) {} + [[nodiscard]] bool matchesLock(const CallEvent &Call) const { + return LockFn.matches(Call); + } + bool matchesUnlock(const CallEvent &Call) const { + return UnlockFn.matches(Call); + } + [[nodiscard]] const MemRegion *getLockRegion(const CallEvent &Call) const { + return cast<CXXMemberCall>(Call).getCXXThisVal().getAsRegion(); + } + [[nodiscard]] const MemRegion *getUnlockRegion(const CallEvent &Call) const { + return cast<CXXMemberCall>(Call).getCXXThisVal().getAsRegion(); + } +}; + +class RAIIMutexDescriptor { + mutable const IdentifierInfo *Guard{}; + mutable bool IdentifierInfoInitialized{}; + mutable llvm::SmallString<32> GuardName{}; + + void initIdentifierInfo(const CallEvent &Call) const { + if (!IdentifierInfoInitialized) { + // In case of checking C code, or when the corresponding headers are not + // included, we might end up query the identifier table every time when + // this function is called instead of early returning it. To avoid this, a + // bool variable (IdentifierInfoInitialized) is used and the function will + // be run only once. + Guard = &Call.getCalleeAnalysisDeclContext()->getASTContext().Idents.get( + GuardName); + IdentifierInfoInitialized = true; + } + } + +public: + RAIIMutexDescriptor(StringRef GuardName) : GuardName(GuardName) {} + [[nodiscard]] bool matchesLock(const CallEvent &Call) const { + initIdentifierInfo(Call); + const auto *Ctor = dyn_cast<CXXConstructorCall>(&Call); + if (!Ctor) + return false; + auto *IdentifierInfo = Ctor->getDecl()->getParent()->getIdentifier(); + return IdentifierInfo == Guard; + } + [[nodiscard]] bool matchesUnlock(const CallEvent &Call) const { + initIdentifierInfo(Call); + const auto *Dtor = dyn_cast<CXXDestructorCall>(&Call); + if (!Dtor) + return false; + auto *IdentifierInfo = + cast<CXXRecordDecl>(Dtor->getDecl()->getParent())->getIdentifier(); + return IdentifierInfo == Guard; + } ---------------- NagyDonat wrote:
The methods `matchesLock()` and `matchesUnlock()` are a bit complex and almost identical, consider implementing them as calling `matchesImpl<CXXConstructorCall>(Call)` and `matchesImpl<CXXDestructorCall>(Call)` with a template function that contains the shared logic. https://github.com/llvm/llvm-project/pull/80029 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits