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
