[clang] [clang][ThreadSafety]: fix discrepancy between capability attributes (PR #139343)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 9 17:40:01 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Cory Fields (theuni)
<details>
<summary>Changes</summary>
Fix the case where `release_generic_capability` did not correctly release when used as a reverse capability as enabled by commit 6a68efc959.
I noticed this when trying to implement a reverse lock.
My my project still uses the old `UNLOCK_FUNCTION` macro which maps to `unlock_function`. With that attribute, the [MutexUnlock test-case seen here](https://github.com/llvm/llvm-project/blob/main/clang/test/SemaCXX/warn-thread-safety-analysis.cpp#L3126) does not work.
I'm not at all familiar with the clang code so I have no idea if this is the correct fix, but it fixes my problem. Hopefully it's helpful.
Here's a minimal reproducer:
```c++
class __attribute__((capability(""))) Mutex {
public:
const Mutex& operator!() const { return *this; }
};
class __attribute__((scoped_lockable)) MutexLock {
public:
MutexLock(Mutex *mu) __attribute__((acquire_capability(mu))) {}
~MutexLock() __attribute__((release_capability())){}
};
class __attribute__((scoped_lockable)) MutexLockOld {
public:
MutexLockOld(Mutex *mu) __attribute__((exclusive_lock_function(mu))) {}
~MutexLockOld() __attribute__((unlock_function())){}
};
class __attribute__((scoped_lockable)) MutexLockGeneric {
public:
MutexLockGeneric(Mutex *mu) __attribute__((acquire_capability(mu))) {}
~MutexLockGeneric() __attribute__((release_generic_capability())){}
};
class __attribute__((scoped_lockable)) MutexUnlock {
public:
MutexUnlock(Mutex *mu) __attribute__((release_capability(mu))){}
~MutexUnlock() __attribute__((release_capability())){}
};
class __attribute__((scoped_lockable)) MutexUnlockOld {
public:
MutexUnlockOld(Mutex *mu) __attribute__((unlock_function(mu))){}
~MutexUnlockOld() __attribute__((unlock_function())){}
};
class __attribute__((scoped_lockable)) MutexUnlockGeneric {
public:
MutexUnlockGeneric(Mutex *mu) __attribute__((release_generic_capability(mu))){}
~MutexUnlockGeneric() __attribute__((release_generic_capability())){}
};
Mutex mut;
void req() __attribute__((requires_capability(mut))){}
void req2() __attribute__((exclusive_locks_required(mut))){}
void not_req() __attribute__((requires_capability(!mut))){}
void good()
{
MutexLock lock(&mut);
req();
{
MutexUnlock reverse_lock(&mut);
not_req();
}
req();
}
void bad()
{
MutexLockGeneric lock(&mut);
req();
{
MutexUnlockGeneric reverse_lock(&mut);
not_req();
}
req();
req2();
}
void bad2()
{
MutexLockOld lock(&mut);
req();
{
MutexUnlockOld reverse_lock(&mut);
not_req();
}
req();
req2();
}
```
Result:
```bash
clangtest.cpp:67:5: warning: calling function 'req' requires holding 'mut' exclusively [-Wthread-safety-analysis]
67 | req();
| ^
clangtest.cpp:68:5: warning: calling function 'req2' requires holding 'mut' exclusively [-Wthread-safety-analysis]
68 | req2();
| ^
clangtest.cpp:79:5: warning: calling function 'req' requires holding 'mut' exclusively [-Wthread-safety-analysis]
79 | req();
| ^
clangtest.cpp:80:5: warning: calling function 'req2' requires holding 'mut' exclusively [-Wthread-safety-analysis]
80 | req2();
```
---
Full diff: https://github.com/llvm/llvm-project/pull/139343.diff
1 Files Affected:
- (modified) clang/lib/Analysis/ThreadSafety.cpp (+2)
``````````diff
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp
index 7e86af6b4a317..a963bcda0c2d0 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -2026,6 +2026,8 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
ScopedEntry->addExclusiveUnlock(M);
for (const auto &M : SharedLocksToRemove)
ScopedEntry->addSharedUnlock(M);
+ for (const auto &M : GenericLocksToRemove)
+ ScopedEntry->addExclusiveUnlock(M);
Analyzer->addLock(FSet, std::move(ScopedEntry));
}
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/139343
More information about the cfe-commits
mailing list