[clang] [llvm] [Clang] Improve type safety in RAIIMemberMutexDescriptor (PR #204338)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 17 04:30:26 PDT 2026
https://github.com/JasonHonKL created https://github.com/llvm/llvm-project/pull/204338
Add explicit cast<CXXMethodDecl>() when obtaining the method declaration from CXXMemberCall in RAIIMemberMutexDescriptor::matches().
This change:
- Improves type safety by making pointer conversions explicit
- Provides debug build validation through LLVM's cast<T>() assertion
- Has zero runtime overhead (optimized away in release builds)
- Aligns with LLVM coding style for known-valid type conversions
The RAIIMemberMutexDescriptor class handles explicit lock()/unlock() member calls on RAII mutex wrappers like std::unique_lock, complementing the constructor/destructor handling in RAIIMutexDescriptor. This ensures the BlockInCriticalSection checker correctly tracks lock state when manual lock/unlock methods are used.
Fixes #204304
>From 7cad72cb8dc8e9b72d9410ebec4a21af9642102a Mon Sep 17 00:00:00 2001
From: JasonHonKL <j2004nol at gmail.com>
Date: Wed, 17 Jun 2026 19:20:27 +0800
Subject: [PATCH 1/3] add RAIIMemberMutexDescriptor to handle unique_lock
unlock issue.
---
.../BlockInCriticalSectionChecker.cpp | 54 +++++++++++++++++--
test_block_in_cs.plist | 14 +++++
2 files changed, 65 insertions(+), 3 deletions(-)
create mode 100644 test_block_in_cs.plist
diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 03c576270797b..256edf07d4482 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -157,9 +157,55 @@ class RAIIMutexDescriptor {
}
};
+class RAIIMemberMutexDescriptor {
+ mutable const IdentifierInfo *WrapperType{};
+ mutable bool IdentifierInitialized{};
+ mutable llvm::SmallString<32> WrapperTypeName{};
+
+ void initIdentifierInfo(const CallEvent &Call) const {
+ if (!IdentifierInitialized) {
+ const auto &ASTCtx = Call.getASTContext();
+ WrapperType = &ASTCtx.Idents.get(WrapperTypeName);
+ IdentifierInitialized = true;
+ }
+ }
+
+public:
+ RAIIMemberMutexDescriptor(StringRef WrapperTypeName)
+ : WrapperTypeName(WrapperTypeName) {}
+
+ [[nodiscard]] bool matches(const CallEvent &Call, bool IsLock) const {
+ initIdentifierInfo(Call);
+
+ const auto *MemCall = dyn_cast<CXXMemberCall>(&Call);
+ if (!MemCall)
+ return false;
+
+ const CXXMethodDecl *Method = MemCall->getDecl();
+ const CXXRecordDecl *ClassDecl = Method->getParent();
+ const IdentifierInfo *ClassName = ClassDecl->getIdentifier();
+
+ if (ClassName != WrapperType)
+ return false;
+
+ const IdentifierInfo *MethodName = Method->getIdentifier();
+ if (!MethodName)
+ return false;
+
+ if (IsLock)
+ return MethodName->isStr("lock");
+ else
+ return MethodName->isStr("unlock");
+ }
+
+ [[nodiscard]] const MemRegion *getRegion(const CallEvent &Call, bool) const {
+ return cast<CXXMemberCall>(Call).getCXXThisVal().getAsRegion();
+ }
+};
+
using MutexDescriptor =
std::variant<FirstArgMutexDescriptor, MemberMutexDescriptor,
- RAIIMutexDescriptor>;
+ RAIIMutexDescriptor, RAIIMemberMutexDescriptor>;
class SuppressNonBlockingStreams : public BugReporterVisitor {
private:
@@ -214,7 +260,7 @@ class SuppressNonBlockingStreams : public BugReporterVisitor {
class BlockInCriticalSectionChecker : public Checker<check::PostCall> {
private:
- const std::array<MutexDescriptor, 9> MutexDescriptors{
+ const std::array<MutexDescriptor, 11> MutexDescriptors{
// NOTE: There are standard library implementations where some methods
// of `std::mutex` are inherited from an implementation detail base
// class, and those aren't matched by the name specification {"std",
@@ -239,7 +285,9 @@ class BlockInCriticalSectionChecker : public Checker<check::PostCall> {
{CDM::CLibrary, {"mtx_unlock"}, 1}),
RAIIMutexDescriptor("lock_guard"),
RAIIMutexDescriptor("unique_lock"),
- RAIIMutexDescriptor("scoped_lock")};
+ RAIIMemberMutexDescriptor("unique_lock"),
+ RAIIMutexDescriptor("scoped_lock"),
+ RAIIMemberMutexDescriptor("scoped_lock")};
const CallDescriptionSet BlockingFunctions{{CDM::CLibrary, {"sleep"}},
{CDM::CLibrary, {"getc"}},
diff --git a/test_block_in_cs.plist b/test_block_in_cs.plist
new file mode 100644
index 0000000000000..04ff38cef2842
--- /dev/null
+++ b/test_block_in_cs.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>clang_version</key>
+<string>Homebrew clang version 22.1.7</string>
+ <key>diagnostics</key>
+ <array>
+ </array>
+ <key>files</key>
+ <array>
+ </array>
+</dict>
+</plist>
>From b0133818745292aee2c27cbbb4faea6047463ab5 Mon Sep 17 00:00:00 2001
From: JasonHonKL <j2004nol at gmail.com>
Date: Wed, 17 Jun 2026 19:23:21 +0800
Subject: [PATCH 2/3] Improve type safety in RAIIMemberMutexDescriptor by using
explicit cast
---
.../StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 256edf07d4482..3d0b27af79763 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -181,7 +181,7 @@ class RAIIMemberMutexDescriptor {
if (!MemCall)
return false;
- const CXXMethodDecl *Method = MemCall->getDecl();
+ const CXXMethodDecl *Method = cast<CXXMethodDecl>(MemCall->getDecl());
const CXXRecordDecl *ClassDecl = Method->getParent();
const IdentifierInfo *ClassName = ClassDecl->getIdentifier();
>From fbec6f1fe2e8bf9f8b3b36fa3e4cd4f25a8d3057 Mon Sep 17 00:00:00 2001
From: JasonHonKL <j2004nol at gmail.com>
Date: Wed, 17 Jun 2026 19:28:00 +0800
Subject: [PATCH 3/3] Remove accidentally committed test plist file
The test_block_in_cs.plist file was accidentally added during development.
It's empty and not in the proper location for test fixtures.
---
test_block_in_cs.plist | 14 --------------
1 file changed, 14 deletions(-)
delete mode 100644 test_block_in_cs.plist
diff --git a/test_block_in_cs.plist b/test_block_in_cs.plist
deleted file mode 100644
index 04ff38cef2842..0000000000000
--- a/test_block_in_cs.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>clang_version</key>
-<string>Homebrew clang version 22.1.7</string>
- <key>diagnostics</key>
- <array>
- </array>
- <key>files</key>
- <array>
- </array>
-</dict>
-</plist>
More information about the cfe-commits
mailing list