https://github.com/aaditya8979 created 
https://github.com/llvm/llvm-project/pull/229986

### Description
This PR resolves a false positive in `alpha.cplusplus.SmartPtr` where repeated 
calls to `std::unique_ptr::get()` on the same object returned identity-distinct 
symbols. This instability caused deterministic equivalence checks (e.g., `X == 
Y`) to incorrectly bifurcate into both `TRUE` and `FALSE` execution paths.

### Root Cause
`SmartPtrModeling` intercepts calls to smart pointer methods (`get()`, 
`release()`, `reset()`, `swap()`) via `evalCall`, establishing precise memory 
state transitions in the `TrackedRegionMap`. 

However, `ExprEngine::evalCall` runs an unconditional post-call 
`PSK_EscapeOutParameters` escape scan for every C++ method call on an object 
with a non-trivial destructor. Because `std::unique_ptr<T>` has a non-trivial 
destructor, its inner pointer is unconditionally marked as escaped after every 
modeled method call. 

This triggers a destructive chain:
`runCheckersForPointerEscape` → `checkRegionChanges` → 
`removeTrackedSubregions` → **`TrackedRegionMap` entry wiped.**

Consequently, the map entry established by the handler is destroyed before the 
next statement evaluates. A subsequent call to `P.get()` finds an empty cache 
and conjures a fresh, identity-distinct symbol (`conj_$1`), breaking symbol 
equivalence.

### The Fix
This patch introduces a surgical bypass in 
`SmartPtrModeling::checkRegionChanges`. 

`SmartPtrMethodHandlers` encodes exactly which `CallEvent`s the checker 
explicitly models. If `checkRegionChanges` is invoked for a call that matches 
one of our handlers, the handler has already produced the authoritative, 
deterministic memory state. The conservative region wipe is preempted, 
preserving the cached `TrackedRegionMap` state.

```cpp
if (Call && SmartPtrMethodHandlers.lookup(*Call))
  return State;

>From 1fcc621cf50b6e848e40e25a65d25c801a3fe0c2 Mon Sep 17 00:00:00 2001
From: openhands <[email protected]>
Date: Thu, 8 Oct 2026 10:03:53 +0530
Subject: [PATCH] [clang][analyzer] Fix state invalidation for modeled smart
 pointer methods

Resolves a false positive where repeated calls to `get()` on the same
`std::unique_ptr` produced identity-distinct symbols, causing deterministic
equivalence checks (e.g., X == Y from two get() calls) to bifurcate into
both TRUE and FALSE paths.

Root cause: `ExprEngine`'s post-call escape scan
(`PSK_EscapeOutParameters`, ExprEngineCallAndReturn.cpp L709-727) fires
unconditionally for any C++ object with a non-trivial destructor, regardless
of whether `evalCall` modeled the call. `unique_ptr` has a non-trivial
destructor, so its inner pointer is marked escaped after every modeled method
call. This triggers `checkRegionChanges` which calls
`removeTrackedSubregions`, wiping the `TrackedRegionMap` entry established
by the handler.

Fix: Guard `checkRegionChanges` with a lookup in `SmartPtrMethodHandlers`.
If the triggering `CallEvent` is a method we explicitly model (get(),
release(), swap(), reset()), our handler has already produced the definitive,
deterministic memory state. We trust that state and skip the conservative
region wipe.

Confirmed via `clang_analyzer_printState` diagnostic: before this fix, the
`TrackedRegionMap` entry for the `unique_ptr` was wiped between consecutive
`get()` calls; after the fix, the cache survives and both calls return the
identical `SymbolRef`.
---
 clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp 
b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index ad81e5076f931..de549377d6f77 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -573,6 +573,16 @@ ProgramStateRef SmartPtrModeling::checkRegionChanges(
     ArrayRef<const MemRegion *> ExplicitRegions,
     ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
     const CallEvent *Call) const {
+  // Preempt conservative invalidation. If the invalidation is triggered by a
+  // modeled smart pointer method (e.g., get(), release(), swap()), the handler
+  // has already executed the precise, deterministic memory transitions via
+  // TrackedRegionMap. The ExprEngine's post-call PSK_EscapeOutParameters scan
+  // fires unconditionally for any object with a non-trivial destructor, which
+  // causes removeTrackedSubregions to blindly wipe our established state. If
+  // we own the CallEvent, we trust the state our handler produced.
+  if (Call && SmartPtrMethodHandlers.lookup(*Call))
+    return State;
+
   TrackedRegionMapTy RegionMap = State->get<TrackedRegionMap>();
   TrackedRegionMapTy::Factory &RegionMapFactory =
       State->get_context<TrackedRegionMap>();

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

Reply via email to