https://github.com/necto updated https://github.com/llvm/llvm-project/pull/210912
>From e9e747a0cad3ff0ca74a2b035fca1eacd492f168 Mon Sep 17 00:00:00 2001 From: Arseniy Zaostrovnykh <[email protected]> Date: Mon, 20 Jul 2026 13:20:00 +0200 Subject: [PATCH 1/2] Crashing test case --- clang/test/Analysis/pthreadlock.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/clang/test/Analysis/pthreadlock.c b/clang/test/Analysis/pthreadlock.c index e931569c45ab8..426070ae3012a 100644 --- a/clang/test/Analysis/pthreadlock.c +++ b/clang/test/Analysis/pthreadlock.c @@ -1,8 +1,8 @@ // RUN: %clang_analyze_cc1 \ -// RUN: -analyzer-checker=alpha.unix.PthreadLock \ +// RUN: -analyzer-checker=alpha.unix.PthreadLock,debug.ExprInspection \ // RUN: -verify %s // RUN: %clang_analyze_cc1 \ -// RUN: -analyzer-checker=alpha.unix.PthreadLock \ +// RUN: -analyzer-checker=alpha.unix.PthreadLock,debug.ExprInspection \ // RUN: -analyzer-config alpha.unix.PthreadLock:WarnOnLockOrderReversal=true \ // RUN: -verify=expected,lor %s @@ -18,6 +18,28 @@ lck_rw_t rw; #define NULL 0 +void clang_analyzer_warnIfReached(void); +long global_var; +void noCrash(void) { + // Produce a complicated self-contradictory constraint + if (((global_var & 137) == 2) && + ((global_var & 137) & 8)) { + // This branch is actually dead, but the analyzer does not realize that yet. + clang_analyzer_warnIfReached(); + pthread_mutex_lock(&mtx1); // no-warning + } +} + +void noCrashTryLock(void) { + // Produce a complicated self-contradictory constraint + if (((global_var & 137) == 2) && + ((global_var & 137) & 8)) { + // This branch is actually dead, but the analyzer does not realize that yet. + clang_analyzer_warnIfReached(); + pthread_mutex_trylock(&mtx1); // no-warning + } +} + void ok1(void) { >From 36eca8abce0f944aab2b3cd5b7b40b60764d2eab Mon Sep 17 00:00:00 2001 From: Arseniy Zaostrovnykh <[email protected]> Date: Tue, 21 Jul 2026 10:39:09 +0200 Subject: [PATCH 2/2] Fix PthreadLockChecker --- .../Checkers/PthreadLockChecker.cpp | 17 ++++++++++++++--- clang/test/Analysis/pthreadlock.c | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) 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 426070ae3012a..49b83cab031a0 100644 --- a/clang/test/Analysis/pthreadlock.c +++ b/clang/test/Analysis/pthreadlock.c @@ -25,7 +25,7 @@ void noCrash(void) { if (((global_var & 137) == 2) && ((global_var & 137) & 8)) { // This branch is actually dead, but the analyzer does not realize that yet. - clang_analyzer_warnIfReached(); + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} pthread_mutex_lock(&mtx1); // no-warning } } @@ -35,7 +35,7 @@ void noCrashTryLock(void) { if (((global_var & 137) == 2) && ((global_var & 137) & 8)) { // This branch is actually dead, but the analyzer does not realize that yet. - clang_analyzer_warnIfReached(); + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} pthread_mutex_trylock(&mtx1); // no-warning } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
