llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

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

Author: Balázs Benics (steakhal)

<details>
<summary>Changes</summary>

Implementation of 
https://discourse.llvm.org/t/memory-region-invalidation-tracking-improvements/62432

I plan to lan each commit as a separate PR. I'm just posting this in a single 
PR for now to let you review commit by commit, or to see the grand picture.

The code was written by claude, but I've carefully vetted and tuned it.

---

Patch is 105.78 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/207155.diff


42 Files Affected:

- (modified) clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h (+10) 
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h 
(+9) 
- (added) 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/InvalidationCause.h 
(+206) 
- (modified) 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h (+7-2) 
- (modified) 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (+9-2) 
- (modified) 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h (+11) 
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h 
(+7-1) 
- (modified) 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h (+113) 
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def 
(+2-1) 
- (modified) clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (+42-42) 
- (modified) clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp (+8-3) 
- (modified) clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h (+2-1) 
- (modified) clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (+6-4) 
- (modified) clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp 
(+4-4) 
- (modified) clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp (+8-1) 
- (modified) clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp 
(+2-1) 
- (modified) clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp 
(+1-2) 
- (modified) clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp (+8-5) 
- (modified) clang/lib/StaticAnalyzer/Core/CMakeLists.txt (+1) 
- (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+6-1) 
- (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+22-10) 
- (modified) clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (+5-3) 
- (added) clang/lib/StaticAnalyzer/Core/InvalidationCause.cpp (+47) 
- (modified) clang/lib/StaticAnalyzer/Core/LoopWidening.cpp (+8-4) 
- (modified) clang/lib/StaticAnalyzer/Core/ProgramState.cpp (+6-4) 
- (modified) clang/lib/StaticAnalyzer/Core/RegionStore.cpp (+56-18) 
- (modified) clang/lib/StaticAnalyzer/Core/SValBuilder.cpp (+21) 
- (modified) clang/lib/StaticAnalyzer/Core/SymbolManager.cpp (+22) 
- (modified) clang/test/Analysis/PR57270.cpp (+2-2) 
- (modified) clang/test/Analysis/ctor-trivial-copy.cpp (+6-6) 
- (modified) clang/test/Analysis/dtor-array.cpp (+1-1) 
- (modified) clang/test/Analysis/dump_egraph.cpp (+1-1) 
- (modified) clang/test/Analysis/explain-svals.cpp (+3-3) 
- (modified) clang/test/Analysis/fread.c (+28-28) 
- (modified) clang/test/Analysis/getline-unixapi.c (+4-4) 
- (added) clang/test/Analysis/invalidation-artifact-dump.c (+82) 
- (added) clang/test/Analysis/invalidation-artifact-loop-widening.c (+19) 
- (added) clang/test/Analysis/invalidation-artifact-partial-call.c (+30) 
- (added) clang/test/Analysis/invalidation-artifact-unmodeled-expr.c (+18) 
- (modified) clang/test/Analysis/store-dump-orders.cpp (+2-2) 
- (modified) clang/test/Analysis/stream-invalidate.c (+12-12) 
- (modified) clang/test/Analysis/taint-generic.c (+3-3) 


``````````diff
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h 
b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index 6c1025ecc7f4d..bce3934ba0f4b 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -126,6 +126,16 @@ class SValExplainer : public 
FullSValVisitor<SValExplainer, std::string> {
            printCFGElementRef(S->getCFGElementRef()) + "'";
   }
 
+  std::string
+  VisitSymbolInvalidationArtifact(const SymbolInvalidationArtifact *S) {
+    std::string CauseStr;
+    llvm::raw_string_ostream OS(CauseStr);
+    S->getCause()->dumpToStream(OS);
+    return "invalidation artifact (" + CauseStr + ") of type '" +
+           S->getType().getAsString() + "' at CFG element '" +
+           printCFGElementRef(S->getCFGElementRef()) + "'";
+  }
+
   std::string VisitSymbolDerived(const SymbolDerived *S) {
     return "value derived from (" + Visit(S->getParentSymbol()) +
            ") for " + Visit(S->getRegion());
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 3252421414181..28e653c3a4680 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -29,6 +29,7 @@
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/InvalidationCause.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@@ -263,6 +264,14 @@ class CallEvent {
     return Origin.dyn_cast<const Expr *>();
   }
 
+  template <class CauseT> const CauseT *tryCreateInvalidationCause() const {
+    static_assert(std::is_base_of_v<UnmodeledCall, CauseT>,
+                  "forInvalidation<T> requires T : UnmodeledCall");
+    const auto *CE = dyn_cast_or_null<CallExpr>(getOriginExpr());
+    auto &SymMgr = State->getStateManager().getSymbolManager();
+    return SymMgr.acquireCause<CauseT>(CE);
+  }
+
   /// Returns the number of arguments (explicit and implicit).
   ///
   /// Note that this may be greater than the number of parameters in the
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/InvalidationCause.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/InvalidationCause.h
new file mode 100644
index 0000000000000..42dc48faa12aa
--- /dev/null
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/InvalidationCause.h
@@ -0,0 +1,206 @@
+//===- InvalidationCause.h - Cause of a region invalidation ------*- C++ 
-*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines InvalidationCause, a small class hierarchy describing why
+// a memory region was invalidated by ProgramState::invalidateRegions. The
+// cause is carried by SymbolInvalidationArtifact symbols so that downstream
+// machinery (bug-report suppression, diagnostics) can distinguish symbolic
+// values produced by an invalidation event from ordinary conjured symbols.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_INVALIDATIONCAUSE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_INVALIDATIONCAUSE_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+
+class CallExpr;
+class Stmt;
+
+namespace ento {
+
+class SymbolManager;
+
+/// Describes why a memory region was invalidated. Instances are uniqued by
+/// SymbolManager::acquireCause<T>(...) and are stable for the analysis
+/// lifetime; callers must not allocate them on the stack.
+class InvalidationCause : public llvm::FoldingSetNode {
+public:
+  virtual ~InvalidationCause() = default;
+
+  enum Kind {
+    // UnmodeledCall range
+    ConservativeEvalCallKind,
+    PartiallyModeledCallKind,
+    BEGIN_UNMODELED_CALL = ConservativeEvalCallKind,
+    END_UNMODELED_CALL = PartiallyModeledCallKind,
+
+    // UnmodeledStmt range
+    UnmodeledExprKind,
+    LoopWideningKind,
+    BEGIN_UNMODELED_STMT = UnmodeledExprKind,
+    END_UNMODELED_STMT = LoopWideningKind,
+  };
+
+  Kind getKind() const { return K; }
+
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
+  virtual void dumpToStream(raw_ostream &OS) const = 0;
+
+  LLVM_DUMP_METHOD void dump() const;
+
+protected:
+  explicit InvalidationCause(Kind K) : K(K) {}
+  virtual void anchor();
+
+private:
+  Kind K;
+};
+
+/// Abstract base for invalidations triggered by an unmodeled or partially
+/// modeled call.
+class UnmodeledCall : public InvalidationCause {
+public:
+  /// Returns the expression whose value will be the result of this call.
+  /// Null if and only if 'this' is a CXXDestructorCall.
+  const CallExpr *getCallExpr() const { return CE; }
+
+  static bool classof(const InvalidationCause *C) {
+    return C->getKind() >= BEGIN_UNMODELED_CALL &&
+           C->getKind() <= END_UNMODELED_CALL;
+  }
+
+protected:
+  const CallExpr *CE;
+  UnmodeledCall(Kind K, const CallExpr *CE) : InvalidationCause(K), CE(CE) {}
+  void anchor() override;
+};
+
+/// Conservative evaluation of a call: the call's body wasn't inlined and we
+/// fall back to invalidating its arguments / reachable globals.
+class ConservativeEvalCall final : public UnmodeledCall {
+public:
+  void Profile(llvm::FoldingSetNodeID &ID) const override { Profile(ID, CE); }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, const CallExpr *CE) {
+    ID.AddInteger((unsigned)ConservativeEvalCallKind);
+    ID.AddPointer(CE);
+  }
+
+  void dumpToStream(raw_ostream &OS) const override;
+
+  static bool classof(const InvalidationCause *C) {
+    return C->getKind() == ConservativeEvalCallKind;
+  }
+
+protected:
+  friend class SymbolManager;
+  explicit ConservativeEvalCall(const CallExpr *CE)
+      : UnmodeledCall(ConservativeEvalCallKind, CE) {}
+  void anchor() override;
+};
+
+/// A call that the analyzer models but bails out of for some operands (e.g.
+/// CStringChecker's memcpy fallback, MallocChecker's free invalidation,
+/// SmartPtrModeling's ostream<< handling).
+class PartiallyModeledCall final : public UnmodeledCall {
+public:
+  void Profile(llvm::FoldingSetNodeID &ID) const override { Profile(ID, CE); }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, const CallExpr *CE) {
+    ID.AddInteger((unsigned)PartiallyModeledCallKind);
+    ID.AddPointer(CE);
+  }
+
+  void dumpToStream(raw_ostream &OS) const override;
+
+  static bool classof(const InvalidationCause *C) {
+    return C->getKind() == PartiallyModeledCallKind;
+  }
+
+protected:
+  friend class SymbolManager;
+  explicit PartiallyModeledCall(const CallExpr *CE)
+      : UnmodeledCall(PartiallyModeledCallKind, CE) {}
+  void anchor() override;
+};
+
+/// Abstract base for invalidations triggered by an unmodeled statement
+/// (atomics, inline asm) or a widened loop.
+class UnmodeledStmt : public InvalidationCause {
+public:
+  LLVM_ATTRIBUTE_RETURNS_NONNULL
+  const Stmt *getStmt() const { return S; }
+
+  static bool classof(const InvalidationCause *C) {
+    return C->getKind() >= BEGIN_UNMODELED_STMT &&
+           C->getKind() <= END_UNMODELED_STMT;
+  }
+
+protected:
+  const Stmt *S;
+  UnmodeledStmt(Kind K, const Stmt *S) : InvalidationCause(K), S(S) {
+    assert(S);
+  }
+  void anchor() override;
+};
+
+/// An expression we don't model (e.g. AtomicExpr, GCCAsmStmt).
+class UnmodeledExpr final : public UnmodeledStmt {
+public:
+  void Profile(llvm::FoldingSetNodeID &ID) const override { Profile(ID, S); }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, const Stmt *S) {
+    ID.AddInteger((unsigned)UnmodeledExprKind);
+    ID.AddPointer(S);
+  }
+
+  void dumpToStream(raw_ostream &OS) const override;
+
+  static bool classof(const InvalidationCause *C) {
+    return C->getKind() == UnmodeledExprKind;
+  }
+
+private:
+  friend class SymbolManager;
+  explicit UnmodeledExpr(const Stmt *S) : UnmodeledStmt(UnmodeledExprKind, S) 
{}
+  void anchor() override;
+};
+
+/// The widened loop's invalidation event.
+class LoopWidening final : public UnmodeledStmt {
+public:
+  void Profile(llvm::FoldingSetNodeID &ID) const override { Profile(ID, S); }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, const Stmt *S) {
+    ID.AddInteger((unsigned)LoopWideningKind);
+    ID.AddPointer(S);
+  }
+
+  void dumpToStream(raw_ostream &OS) const override;
+
+  static bool classof(const InvalidationCause *C) {
+    return C->getKind() == LoopWideningKind;
+  }
+
+protected:
+  friend class SymbolManager;
+  explicit LoopWidening(const Stmt *S) : UnmodeledStmt(LoopWideningKind, S) {}
+  void anchor() override;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const InvalidationCause &C);
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_INVALIDATIONCAUSE_H
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
index b9e7732a4fee3..22b67eb7e44a7 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
@@ -15,17 +15,22 @@
 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H
 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H
 
+#include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Analysis/CFG.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 
 namespace clang {
+class StackFrame;
 namespace ento {
 
 /// Get the states that result from widening the loop.
 ///
 /// Widen the loop by invalidating anything that might be modified
 /// by the loop body in any iteration.
-ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
+/// statement of the widened loop (if available); when non-null it is
+/// attached to the resulting invalidation symbols as a LoopWidening cause.
+ProgramStateRef getWidenedLoopState(const Stmt *LoopStmt,
+                                    ProgramStateRef PrevState,
                                     const StackFrame *SF, unsigned BlockCount,
                                     ConstCFGElementRef Elem);
 
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 3458fa9fe27a4..15cbcd10f5055 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -38,6 +38,7 @@ namespace ento {
 class AnalysisManager;
 class CallEvent;
 class CallEventManager;
+class InvalidationCause;
 
 typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)(
     ProgramStateManager &, ExprEngine *);
@@ -327,18 +328,24 @@ class ProgramState : public llvm::FoldingSetNode {
   ///        the call and should be considered directly invalidated.
   /// \param ITraits information about special handling for particular regions
   ///        or symbols.
+  /// \param Cause if non-null, identifies the reason for the invalidation;
+  ///        regions invalidated under such a cause receive a
+  ///        SymbolInvalidationArtifact symbol carrying the cause instead of a
+  ///        plain SymbolConjured.
   [[nodiscard]] ProgramStateRef invalidateRegions(
       ArrayRef<const MemRegion *> Regions, ConstCFGElementRef Elem,
       unsigned BlockCount, const StackFrame *SF, bool CausesPointerEscape,
       InvalidatedSymbols *IS = nullptr, const CallEvent *Call = nullptr,
-      RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
+      RegionAndSymbolInvalidationTraits *ITraits = nullptr,
+      const InvalidationCause *Cause = nullptr) const;
 
   [[nodiscard]] ProgramStateRef
   invalidateRegions(ArrayRef<SVal> Values, ConstCFGElementRef Elem,
                     unsigned BlockCount, const StackFrame *SF,
                     bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
                     const CallEvent *Call = nullptr,
-                    RegionAndSymbolInvalidationTraits *ITraits = nullptr) 
const;
+                    RegionAndSymbolInvalidationTraits *ITraits = nullptr,
+                    const InvalidationCause *Cause = nullptr) const;
 
   /// enterStackFrame - Returns the state for entry to the given stack frame,
   ///  preserving the current state.
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index a92acfea8f702..927da06b20755 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -48,6 +48,7 @@ namespace ento {
 
 class CallEvent;
 class ConditionTruthVal;
+class InvalidationCause;
 class ProgramStateManager;
 class StoreRef;
 class SValBuilder {
@@ -207,6 +208,16 @@ class SValBuilder {
                                         unsigned visitCount,
                                         const void *symbolTag = nullptr);
 
+  /// Manufacture a value bound to a region during an invalidation event. The
+  /// resulting symbol is a SymbolInvalidationArtifact carrying \p Cause and,
+  /// when \p PreviousSym is non-null, the symbol that was bound to the region
+  /// before the invalidation.
+  DefinedOrUnknownSVal
+  conjureInvalidationArtifactVal(const void *symbolTag, ConstCFGElementRef 
elem,
+                                 const StackFrame *SF, QualType type,
+                                 unsigned count, const InvalidationCause 
*Cause,
+                                 SymbolRef PreviousSym = nullptr);
+
   /// Conjure a symbol representing heap allocated memory region.
   DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem,
                                        const StackFrame *SF, QualType type,
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index cda21138fe5e3..657c8c0772124 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -43,6 +43,7 @@ class StackFrame;
 namespace ento {
 
 class CallEvent;
+class InvalidationCause;
 class ProgramStateManager;
 class ScanReachableSymbols;
 class SymbolReaper;
@@ -239,11 +240,16 @@ class StoreManager {
   ///   invalidated. This should include any regions explicitly invalidated
   ///   even if they do not currently have bindings. Pass \c NULL if this
   ///   information will not be used.
+  /// \param[in] Cause If non-null, the reason for the invalidation. Conjured
+  ///   replacement symbols become SymbolInvalidationArtifact carrying this
+  ///   cause; if null, plain SymbolConjured values are produced (legacy
+  ///   behavior).
   virtual StoreRef invalidateRegions(
       Store store, ArrayRef<SVal> Values, ConstCFGElementRef Elem,
       unsigned Count, const StackFrame *SF, const CallEvent *Call,
       InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits,
-      InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 
0;
+      InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated,
+      const InvalidationCause *Cause = nullptr) = 0;
 
   /// enterStackFrame - Let the StoreManager to do something when execution
   /// engine is about to execute into a callee.
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index a5d49200a50cb..2313138bf9ef0 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -19,6 +19,7 @@
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/InvalidationCause.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
@@ -132,6 +133,84 @@ class SymbolConjured : public SymbolData {
   static constexpr bool classof(Kind K) { return K == ClassKind; }
 };
 
+/// A symbol representing a value bound to a memory region as a side effect of
+/// an invalidation event (escape into an opaque function, loop widening,
+/// unmodeled atomic, etc.). Behaves like SymbolConjured but additionally
+/// carries an InvalidationCause describing why the invalidation happened, and
+/// (when known) the symbol that was bound to the region just before the
+/// invalidation. The previous symbol lets bug-report visitors reason about
+/// constraints attached to a value before it was invalidated.
+class SymbolInvalidationArtifact : public SymbolData {
+  ConstCFGElementRef Elem;
+  QualType T;
+  unsigned Count;
+  const StackFrame *SF;
+  const void *SymbolTag;
+  const InvalidationCause *Cause;
+  SymbolRef PreviousSym;
+
+  friend class SymExprAllocator;
+  SymbolInvalidationArtifact(SymbolID sym, ConstCFGElementRef elem,
+                             const StackFrame *SF, QualType t, unsigned count,
+                             const void *symbolTag,
+                             const InvalidationCause *cause,
+                             SymbolRef previousSym)
+      : SymbolData(ClassKind, sym), Elem(elem), T(t), Count(count), SF(SF),
+        SymbolTag(symbolTag), Cause(cause), PreviousSym(previousSym) {
+    assert(SF);
+    assert(cause);
+    assert(isValidTypeForSymbol(t));
+  }
+
+public:
+  ConstCFGElementRef getCFGElementRef() const { return Elem; }
+
+  unsigned getCount() const { return Count; }
+
+  /// May be null.
+  const void *getTag() const { return SymbolTag; }
+
+  LLVM_ATTRIBUTE_RETURNS_NONNULL
+  const InvalidationCause *getCause() const { return Cause; }
+
+  LLVM_ATTRIBUTE_RETURNS_NONNULL
+  const StackFrame *getStackFrame() const { return SF; }
+
+  /// The symbol that was bound to the invalidated region immediately before
+  /// the invalidation event, or null if the region had no symbolic binding
+  /// (e.g. a concrete value, or no prior binding at all).
+  SymbolRef getPreviousSymbol() const { return PreviousSym; }
+
+  QualType getType() const override;
+
+  StringRef getKindStr() const override;
+
+  void dumpToStream(raw_ostream &os) const override;
+
+  static void Profile(llvm::FoldingSetNodeID &profile, ConstCFGElementRef Elem,
+                      const StackFrame *SF, QualType T, unsigned Count,
+                      const void *SymbolTag, const InvalidationCause *Cause,
+                      SymbolRef PreviousSym) {
+    profile.AddInteger((unsigned)ClassKind);
+    profile.Add(Elem);
+    profile.AddPointer(SF);
+    profile.Add(T);
+    profile.AddInteger(Count);
+    profile.AddPointer(SymbolTag);
+    profile.AddPointer(Cause);
+    profile.AddPointer(PreviousSym);
+  }
+
+  void Profile(llvm::FoldingSetNodeID &profile) override {
+    Profile(profile, Elem, SF, T, Count, SymbolTag, Cause, PreviousSym);
+  }
+
+  // Implement isa<T> support.
+  static constexpr Kind ClassKind = SymbolInvalidationArtifactKind;
+  static bool classof(const SymExpr *SE) { return classof(SE->getKind()); }
+  static constexpr bool classof(Kind K) { return K == ClassKind; }
+};
+
 /// A symbol representing the value of a MemRegion whose parent region has
 /// symbolic value.
 class SymbolDerived : public SymbolData {
@@ -501,16 +580,20 @@ class SymExprAllocator {
     return new (Alloc) SymT(nextID(), std::forward<ArgsT>(Args)...);
   }
 
+  llvm::BumpPtrAllocator &getAllocator() { return Alloc; }
+
 private:
   SymbolID nextID() { retur...
[truncated]

``````````

</details>


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

Reply via email to