[clang] [analyzer] Introduce the invalidation artifact symbol (PR #207155)
Gábor Horváth via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 16 03:03:16 PDT 2026
================
@@ -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 {
----------------
Xazax-hun wrote:
Does a new base class carry its weight if it adds no extra information other than its kind? Or should we just have a field for the unmodeled call for now?
https://github.com/llvm/llvm-project/pull/207155
More information about the cfe-commits
mailing list