-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[clang][ThreadSafety]: fix discrepancy between capability attributes #139343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Fix the case where release_generic_capability did not correctly release when used as a reverse capability as enabled by commit 6a68efc.
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-clang Author: Cory Fields (theuni) ChangesFix the case where I noticed this when trying to implement a reverse lock. My my project still uses the old 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: 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: 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:
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));
}
}
|
@llvm/pr-subscribers-clang-analysis Author: Cory Fields (theuni) ChangesFix the case where I noticed this when trying to implement a reverse lock. My my project still uses the old 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: 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: 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:
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));
}
}
|
Fix the case where
release_generic_capability
did not correctly release when used as a reverse capability as enabled by commit 6a68efc.I noticed this when trying to implement a reverse lock.
My my project still uses the old
UNLOCK_FUNCTION
macro which maps tounlock_function
. With that attribute, the MutexUnlock test-case seen here 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:
Result: