[clang] [clang][analyzer] Improve BlockInCriticalSectionsChecker (PR #80029)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 11 05:31:28 PDT 2024
================
@@ -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
More information about the cfe-commits
mailing list