llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Arseniy Zaostrovnykh (necto)

<details>
<summary>Changes</summary>

PthreadLockChecker assumes `pthread_mutex_lock` is always called in a feasible 
state, which is not true.
In particular, in ZFS the analyzer crashes when runs in CTU mode because it 
reaches `pthread_mutex_lock()` in over-constraint state (see the reduced 
example in the first commit).

--
CPP-8665

---
Full diff: https://github.com/llvm/llvm-project/pull/210912.diff


2 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp (+14-3) 
- (modified) clang/test/Analysis/pthreadlock.c (+19) 


``````````diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 6a1c7a93fb773..c3540ddc32e3a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -493,8 +493,11 @@ void PthreadLockChecker::AcquireLockAux(const CallEvent 
&Call,
       default:
         llvm_unreachable("Unknown tryLock locking semantics");
       }
-      assert(lockFail && lockSucc);
-      C.addTransition(lockFail);
+      // The state where the lock failed can be infeasible if the constraint
+      // solver only now discovers a contradiction in the accumulated
+      // constraints; only take that transition when it is feasible.
+      if (lockFail)
+        C.addTransition(lockFail);
     }
     // We might want to handle the case when the mutex lock function was 
inlined
     // and returned an Unknown or Undefined value.
@@ -505,7 +508,9 @@ void PthreadLockChecker::AcquireLockAux(const CallEvent 
&Call,
       // FIXME: If the lock function was inlined and returned true,
       // we need to behave sanely - at least generate sink.
       lockSucc = state->assume(*DefinedRetVal, false);
-      assert(lockSucc);
+      // `lockSucc` can be null here if the constraint solver only now detects
+      // a contradiction in the accumulated constraints; the shared guard below
+      // prunes this infeasible path.
     }
     // We might want to handle the case when the mutex lock function was 
inlined
     // and returned an Unknown or Undefined value.
@@ -515,6 +520,12 @@ void PthreadLockChecker::AcquireLockAux(const CallEvent 
&Call,
     lockSucc = state;
   }
 
+  // If the constraint solver determined the lock-acquired path is infeasible
+  // (which can surface here when it only now detects a contradiction in the
+  // accumulated constraints), prune this path.
+  if (!lockSucc)
+    return;
+
   // Record that the lock was acquired.
   lockSucc = lockSucc->add<LockSet>(lockR);
   lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked());
diff --git a/clang/test/Analysis/pthreadlock.c 
b/clang/test/Analysis/pthreadlock.c
index e931569c45ab8..6320a3d34600b 100644
--- a/clang/test/Analysis/pthreadlock.c
+++ b/clang/test/Analysis/pthreadlock.c
@@ -18,6 +18,25 @@ lck_rw_t rw;
 
 #define NULL 0
 
+long global_var;
+void noCrash(void) {
+  // Produce a complicated self-contradictory constraint
+  if ((global_var >> 48 & (1ULL << 8) - 1) == 2) {
+  }
+  if (global_var >> 48 & (1ULL << 8) - 1 & 8) {
+  }
+  pthread_mutex_lock(&mtx1); // no-warning
+}
+
+void noCrashTryLock(void) {
+  // Produce a complicated self-contradictory constraint
+  if ((global_var >> 48 & (1ULL << 8) - 1) == 2) {
+  }
+  if (global_var >> 48 & (1ULL << 8) - 1 & 8) {
+  }
+  pthread_mutex_trylock(&mtx1); // no-warning
+}
+
 void
 ok1(void)
 {

``````````

</details>


https://github.com/llvm/llvm-project/pull/210912
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to