[clang] Thread Safety Analysis: Handle address-of followed by dereference (PR #127397)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Feb 16 06:30:00 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-analysis
Author: Marco Elver (melver)
<details>
<summary>Changes</summary>
Correctly analyze expressions where the address of a guarded variable is taken and immediately dereferenced, such as (*(type-specifier *)&x). Previously, such patterns would result in false negatives.
---
Full diff: https://github.com/llvm/llvm-project/pull/127397.diff
2 Files Affected:
- (modified) clang/lib/Analysis/ThreadSafety.cpp (+10)
- (modified) clang/test/Sema/warn-thread-safety-analysis.c (+13)
``````````diff
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp
index bfaf1a0e7c7ff..260505b71c17c 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -1765,6 +1765,8 @@ void ThreadSafetyAnalyzer::checkAccess(const FactSet &FSet, const Expr *Exp,
void ThreadSafetyAnalyzer::checkPtAccess(const FactSet &FSet, const Expr *Exp,
AccessKind AK,
ProtectedOperationKind POK) {
+ // Strips off paren- and cast-expressions, checking if we encounter any other
+ // operator that should be delegated to checkAccess() instead.
while (true) {
if (const auto *PE = dyn_cast<ParenExpr>(Exp)) {
Exp = PE->getSubExpr();
@@ -1780,6 +1782,14 @@ void ThreadSafetyAnalyzer::checkPtAccess(const FactSet &FSet, const Expr *Exp,
Exp = CE->getSubExpr();
continue;
}
+ if (const auto *UO = dyn_cast<UnaryOperator>(Exp)) {
+ if (UO->getOpcode() == UO_AddrOf) {
+ // Pointer access via pointer taken of variable, so the dereferenced
+ // variable is not actually a pointer.
+ checkAccess(FSet, UO->getSubExpr(), AK, POK);
+ return;
+ }
+ }
break;
}
diff --git a/clang/test/Sema/warn-thread-safety-analysis.c b/clang/test/Sema/warn-thread-safety-analysis.c
index 73b4e4798f644..8a0d44cd4bea9 100644
--- a/clang/test/Sema/warn-thread-safety-analysis.c
+++ b/clang/test/Sema/warn-thread-safety-analysis.c
@@ -24,6 +24,9 @@
__attribute__ ((shared_locks_required(__VA_ARGS__)))
#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
+#define __READ_ONCE(x) (*(const volatile __typeof__(x) *)&(x))
+#define __WRITE_ONCE(x, val) do { *(volatile __typeof__(x) *)&(x) = (val); } while (0)
+
// Define the mutex struct.
// Simplified only for test purpose.
struct LOCKABLE Mutex {};
@@ -142,9 +145,19 @@ int main(void) {
(void)(get_value(b_) == 1);
mutex_unlock(foo_.mu_);
+ a_ = 0; // expected-warning{{writing variable 'a_' requires holding mutex 'foo_.mu_'}}
+ __WRITE_ONCE(a_, 0); // expected-warning{{writing variable 'a_' requires holding mutex 'foo_.mu_'}}
+ (void)(a_ == 0); // expected-warning{{reading variable 'a_' requires holding mutex 'foo_.mu_'}}
+ (void)(__READ_ONCE(a_) == 0); // expected-warning{{reading variable 'a_' requires holding mutex 'foo_.mu_'}}
+ (void)(*b_ == 0); // expected-warning{{reading the value pointed to by 'b_' requires holding mutex 'foo_.mu_'}}
c_ = 0; // expected-warning{{writing variable 'c_' requires holding any mutex exclusively}}
(void)(*d_ == 0); // expected-warning{{reading the value pointed to by 'd_' requires holding any mutex}}
mutex_exclusive_lock(foo_.mu_);
+ a_ = 0;
+ __WRITE_ONCE(a_, 0);
+ (void)(a_ == 0);
+ (void)(__READ_ONCE(a_) == 0);
+ (void)(*b_ == 0);
c_ = 1;
(void)(*d_ == 1);
mutex_unlock(foo_.mu_);
``````````
</details>
https://github.com/llvm/llvm-project/pull/127397
More information about the cfe-commits
mailing list