[clang] [nfc][analyzer] Add MemSpace trait to program state (PR #123003)
Michael Flanders via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 27 12:53:21 PST 2025
https://github.com/Flandini updated https://github.com/llvm/llvm-project/pull/123003
>From 7e0758d2ead53bd4288989b8b2eda218cd6dc34a Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 13 Jan 2025 12:34:50 -0600
Subject: [PATCH 01/21] [analyzer] Add MemSpace trait to program state
This trait associates MemSpaceRegions with MemRegions to allow refining or
changing information known about memory regions after they are created, since
they are immutable. This commit is an intermediate step towards moving
MemSpaceRegion out of the MemRegion class hierarchy and moving all notion of
MemSpaceRegion to the trait. The intermediate step is that for now, only
MemRegions with UnknownSpaceRegion are mapped in the trait and checked in
checkers/core.
---
.../Core/PathSensitive/MemSpaces.h | 47 ++++++++++++++
.../Checkers/ArrayBoundCheckerV2.cpp | 1 +
.../Checkers/MacOSXAPIChecker.cpp | 10 +--
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 32 +++++++---
.../StaticAnalyzer/Checkers/MoveChecker.cpp | 41 ++++++------
.../Checkers/PutenvStackArrayChecker.cpp | 10 ++-
.../RetainCountDiagnostics.cpp | 12 +++-
.../Checkers/StackAddrEscapeChecker.cpp | 26 +++++---
.../Checkers/UnixAPIChecker.cpp | 3 +-
.../Core/BugReporterVisitors.cpp | 12 +++-
clang/lib/StaticAnalyzer/Core/CMakeLists.txt | 1 +
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 10 +++
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 62 +++++++++++++++++++
13 files changed, 221 insertions(+), 46 deletions(-)
create mode 100644 clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
create mode 100644 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
new file mode 100644
index 00000000000000..178a6b60c1cb1a
--- /dev/null
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -0,0 +1,47 @@
+//===-- MemSpaces.h -----------------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
+#define LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+
+namespace clang {
+namespace ento {
+
+class MemRegion;
+class MemSpaceRegion;
+
+namespace memspace {
+
+[[nodiscard]] ProgramStateRef setMemSpaceTrait(ProgramStateRef State,
+ const MemRegion *MR,
+ const MemSpaceRegion *MS);
+
+[[nodiscard]] const MemSpaceRegion *getMemSpaceTrait(ProgramStateRef State,
+ const MemRegion *MR);
+
+[[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
+
+template <typename FirstT, typename... RestT>
+[[nodiscard]] bool isMemSpaceOrTrait(ProgramStateRef State,
+ const MemRegion *MR) {
+ return isa<FirstT, RestT...>(MR->getMemorySpace()) ||
+ isa_and_nonnull<FirstT, RestT...>(getMemSpaceTrait(State, MR));
+}
+
+} // namespace memspace
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 6422933c8828a9..e97be53fee4c7f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -22,6 +22,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FormatVariadic.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 754b167642961c..858b6a37551f5d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -22,6 +22,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@@ -75,10 +76,11 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (!R)
return;
+ ProgramStateRef State = C.getState();
+
// Global variables are fine.
const MemRegion *RB = R->getBaseRegion();
- const MemSpaceRegion *RS = RB->getMemorySpace();
- if (isa<GlobalsSpaceRegion>(RS))
+ if (memspace::isMemSpaceOrTrait<GlobalsSpaceRegion>(State, RB))
return;
// Handle _dispatch_once. In some versions of the OS X SDK we have the case
@@ -117,9 +119,9 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (IVR != R)
os << " memory within";
os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
- } else if (isa<HeapSpaceRegion>(RS)) {
+ } else if (memspace::isMemSpaceOrTrait<HeapSpaceRegion>(State, RB)) {
os << " heap-allocated memory";
- } else if (isa<UnknownSpaceRegion>(RS)) {
+ } else if (isa<UnknownSpaceRegion>(RB->getMemorySpace())) {
// Presence of an IVar superregion has priority over this branch, because
// ObjC objects are on the heap even if the core doesn't realize this.
// Presence of a block variable base region has priority over this branch,
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 4166cf14391e2d..76fee2f1322e17 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -72,6 +72,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
@@ -784,7 +785,8 @@ class MallocChecker
bool IsALeakCheck = false) const;
///@}
static bool SummarizeValue(raw_ostream &os, SVal V);
- static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
+ static bool SummarizeRegion(ProgramStateRef State, raw_ostream &os,
+ const MemRegion *MR);
void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range,
const Expr *DeallocExpr,
@@ -2206,13 +2208,21 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
// Parameters, locals, statics, globals, and memory returned by
// __builtin_alloca() shouldn't be freed.
- if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
+ // Should skip this check if:
+ // - The region is in the heap
+ // - The region has unknown memspace and no trait for further clarification
+ // (i.e., just unknown)
+ // - The region has unknown memspace and a heap memspace trait
+ const MemSpaceRegion *MSTrait = memspace::getMemSpaceTrait(State, R);
+ bool HasHeapOrUnknownTrait = !MSTrait || isa<HeapSpaceRegion>(MSTrait);
+ if (!(isa<HeapSpaceRegion>(MS) ||
+ (isa<UnknownSpaceRegion>(MS) && HasHeapOrUnknownTrait))) {
// Regions returned by malloc() are represented by SymbolicRegion objects
// within HeapSpaceRegion. Of course, free() can work on memory allocated
// outside the current function, so UnknownSpaceRegion is also a
// possibility here.
- if (isa<AllocaRegion>(R))
+ if (isa<AllocaRegion>(R) || isa_and_nonnull<AllocaRegion>(MSTrait))
HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
else
HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
@@ -2384,7 +2394,7 @@ bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
return true;
}
-bool MallocChecker::SummarizeRegion(raw_ostream &os,
+bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
const MemRegion *MR) {
switch (MR->getKind()) {
case MemRegion::FunctionCodeRegionKind: {
@@ -2404,8 +2414,10 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
return true;
default: {
const MemSpaceRegion *MS = MR->getMemorySpace();
+ const MemSpaceRegion *MSTrait = memspace::getMemSpaceTrait(State, MR);
- if (isa<StackLocalsSpaceRegion>(MS)) {
+ if (isa<StackLocalsSpaceRegion>(MS) ||
+ isa_and_nonnull<StackLocalsSpaceRegion>(MSTrait)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -2420,7 +2432,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
return true;
}
- if (isa<StackArgumentsSpaceRegion>(MS)) {
+ if (isa<StackArgumentsSpaceRegion>(MS) ||
+ isa_and_nonnull<StackArgumentsSpaceRegion>(MSTrait)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -2435,7 +2448,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
return true;
}
- if (isa<GlobalsSpaceRegion>(MS)) {
+ if (isa<GlobalsSpaceRegion>(MS) ||
+ isa_and_nonnull<GlobalsSpaceRegion>(MSTrait)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -2489,8 +2503,8 @@ void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
os << "deallocator";
os << " is ";
- bool Summarized = MR ? SummarizeRegion(os, MR)
- : SummarizeValue(os, ArgVal);
+ bool Summarized =
+ MR ? SummarizeRegion(C.getState(), os, MR) : SummarizeValue(os, ArgVal);
if (Summarized)
os << ", which is not memory allocated by ";
else
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 52416e21399147..d4ff8186ea69c9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -22,6 +22,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "llvm/ADT/StringSet.h"
using namespace clang;
@@ -145,12 +146,14 @@ class MoveChecker
// Obtains ObjectKind of an object. Because class declaration cannot always
// be easily obtained from the memory region, it is supplied separately.
- ObjectKind classifyObject(const MemRegion *MR, const CXXRecordDecl *RD) const;
+ ObjectKind classifyObject(ProgramStateRef State, const MemRegion *MR,
+ const CXXRecordDecl *RD) const;
// Classifies the object and dumps a user-friendly description string to
// the stream.
- void explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
- const CXXRecordDecl *RD, MisuseKind MK) const;
+ void explainObject(ProgramStateRef State, llvm::raw_ostream &OS,
+ const MemRegion *MR, const CXXRecordDecl *RD,
+ MisuseKind MK) const;
bool belongsTo(const CXXRecordDecl *RD, const llvm::StringSet<> &Set) const;
@@ -299,12 +302,12 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
SmallString<128> Str;
llvm::raw_svector_ostream OS(Str);
- ObjectKind OK = Chk.classifyObject(Region, RD);
+ ObjectKind OK = Chk.classifyObject(State, Region, RD);
switch (OK.StdKind) {
case SK_SmartPtr:
if (MK == MK_Dereference) {
OS << "Smart pointer";
- Chk.explainObject(OS, Region, RD, MK);
+ Chk.explainObject(State, OS, Region, RD, MK);
OS << " is reset to null when moved from";
break;
}
@@ -315,12 +318,12 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
case SK_NonStd:
case SK_Safe:
OS << "Object";
- Chk.explainObject(OS, Region, RD, MK);
+ Chk.explainObject(State, OS, Region, RD, MK);
OS << " is moved";
break;
case SK_Unsafe:
OS << "Object";
- Chk.explainObject(OS, Region, RD, MK);
+ Chk.explainObject(State, OS, Region, RD, MK);
OS << " is left in a valid but unspecified state after move";
break;
}
@@ -353,7 +356,7 @@ void MoveChecker::modelUse(ProgramStateRef State, const MemRegion *Region,
CheckerContext &C) const {
assert(!C.isDifferent() && "No transitions should have been made by now");
const RegionState *RS = State->get<TrackedRegionMap>(Region);
- ObjectKind OK = classifyObject(Region, RD);
+ ObjectKind OK = classifyObject(State, Region, RD);
// Just in case: if it's not a smart pointer but it does have operator *,
// we shouldn't call the bug a dereference.
@@ -406,24 +409,25 @@ ExplodedNode *MoveChecker::tryToReportBug(const MemRegion *Region,
// Creating the error message.
llvm::SmallString<128> Str;
llvm::raw_svector_ostream OS(Str);
+ ProgramStateRef ErrorNodeState = N->getState();
switch(MK) {
case MK_FunCall:
OS << "Method called on moved-from object";
- explainObject(OS, Region, RD, MK);
+ explainObject(ErrorNodeState, OS, Region, RD, MK);
break;
case MK_Copy:
OS << "Moved-from object";
- explainObject(OS, Region, RD, MK);
+ explainObject(ErrorNodeState, OS, Region, RD, MK);
OS << " is copied";
break;
case MK_Move:
OS << "Moved-from object";
- explainObject(OS, Region, RD, MK);
+ explainObject(ErrorNodeState, OS, Region, RD, MK);
OS << " is moved";
break;
case MK_Dereference:
OS << "Dereference of null smart pointer";
- explainObject(OS, Region, RD, MK);
+ explainObject(ErrorNodeState, OS, Region, RD, MK);
break;
}
@@ -482,7 +486,7 @@ void MoveChecker::checkPostCall(const CallEvent &Call,
return;
const CXXRecordDecl *RD = MethodDecl->getParent();
- ObjectKind OK = classifyObject(ArgRegion, RD);
+ ObjectKind OK = classifyObject(State, ArgRegion, RD);
if (shouldBeTracked(OK)) {
// Mark object as moved-from.
State = State->set<TrackedRegionMap>(ArgRegion, RegionState::getMoved());
@@ -549,7 +553,7 @@ bool MoveChecker::belongsTo(const CXXRecordDecl *RD,
}
MoveChecker::ObjectKind
-MoveChecker::classifyObject(const MemRegion *MR,
+MoveChecker::classifyObject(ProgramStateRef State, const MemRegion *MR,
const CXXRecordDecl *RD) const {
// Local variables and local rvalue references are classified as "Local".
// For the purposes of this checker, we classify move-safe STL types
@@ -557,7 +561,7 @@ MoveChecker::classifyObject(const MemRegion *MR,
MR = unwrapRValueReferenceIndirection(MR);
bool IsLocal =
isa_and_nonnull<VarRegion, CXXLifetimeExtendedObjectRegion>(MR) &&
- isa<StackSpaceRegion>(MR->getMemorySpace());
+ memspace::isMemSpaceOrTrait<StackSpaceRegion>(State, MR);
if (!RD || !RD->getDeclContext()->isStdNamespace())
return { IsLocal, SK_NonStd };
@@ -571,8 +575,9 @@ MoveChecker::classifyObject(const MemRegion *MR,
return { IsLocal, SK_Unsafe };
}
-void MoveChecker::explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
- const CXXRecordDecl *RD, MisuseKind MK) const {
+void MoveChecker::explainObject(ProgramStateRef State, llvm::raw_ostream &OS,
+ const MemRegion *MR, const CXXRecordDecl *RD,
+ MisuseKind MK) const {
// We may need a leading space every time we actually explain anything,
// and we never know if we are to explain anything until we try.
if (const auto DR =
@@ -581,7 +586,7 @@ void MoveChecker::explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
OS << " '" << RegionDecl->getDeclName() << "'";
}
- ObjectKind OK = classifyObject(MR, RD);
+ ObjectKind OK = classifyObject(State, MR, RD);
switch (OK.StdKind) {
case SK_NonStd:
case SK_Safe:
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index bf81d57bf82fd3..4449cb4ae68eb9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
using namespace clang;
using namespace ento;
@@ -45,10 +46,15 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
SVal ArgV = Call.getArgSVal(0);
const Expr *ArgExpr = Call.getArgExpr(0);
- const auto *SSR =
- dyn_cast<StackSpaceRegion>(ArgV.getAsRegion()->getMemorySpace());
+ const MemRegion *MR = ArgV.getAsRegion();
+
+ const auto *SSR = dyn_cast<StackSpaceRegion>(MR->getMemorySpace());
+ if (!SSR)
+ SSR = dyn_cast_if_present<StackSpaceRegion>(
+ memspace::getMemSpaceTrait(C.getState(), MR));
if (!SSR)
return;
+
const auto *StackFrameFuncD =
dyn_cast_or_null<FunctionDecl>(SSR->getStackFrame()->getDecl());
if (StackFrameFuncD && StackFrameFuncD->isMain())
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 456132ef0a0a22..ecc7563ceb4bba 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -13,6 +13,7 @@
#include "RetainCountDiagnostics.h"
#include "RetainCountChecker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include <optional>
@@ -690,9 +691,14 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
const MemRegion *R = FB.getRegion();
// Do not show local variables belonging to a function other than
// where the error is reported.
- if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace()))
- if (MR->getStackFrame() == LeakContext->getStackFrame())
- FirstBinding = R;
+ const StackSpaceRegion *MR =
+ dyn_cast<StackSpaceRegion>(R->getMemorySpace());
+ if (!MR)
+ MR = dyn_cast_if_present<StackSpaceRegion>(
+ memspace::getMemSpaceTrait(St, R));
+
+ if (MR && MR->getStackFrame() == LeakContext->getStackFrame())
+ FirstBinding = R;
}
// AllocationNode is the last node in which the symbol was tracked.
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index f4de3b500499c4..4d8c8eea14ea63 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -61,7 +62,7 @@ class StackAddrEscapeChecker
ASTContext &Ctx);
static SmallVector<const MemRegion *, 4>
getCapturedStackRegions(const BlockDataRegion &B, CheckerContext &C);
- static bool isNotInCurrentFrame(const MemRegion *R, CheckerContext &C);
+ static bool isNotInCurrentFrame(const MemSpaceRegion *MS, CheckerContext &C);
};
} // namespace
@@ -117,9 +118,9 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
return range;
}
-bool StackAddrEscapeChecker::isNotInCurrentFrame(const MemRegion *R,
+bool StackAddrEscapeChecker::isNotInCurrentFrame(const MemSpaceRegion *MS,
CheckerContext &C) {
- const StackSpaceRegion *S = cast<StackSpaceRegion>(R->getMemorySpace());
+ const StackSpaceRegion *S = cast<StackSpaceRegion>(MS);
return S->getStackFrame() != C.getStackFrame();
}
@@ -138,10 +139,11 @@ SmallVector<const MemRegion *, 4>
StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
CheckerContext &C) {
SmallVector<const MemRegion *, 4> Regions;
+ ProgramStateRef State = C.getState();
for (auto Var : B.referenced_vars()) {
- SVal Val = C.getState()->getSVal(Var.getCapturedRegion());
+ SVal Val = State->getSVal(Var.getCapturedRegion());
const MemRegion *Region = Val.getAsRegion();
- if (Region && isa<StackSpaceRegion>(Region->getMemorySpace()))
+ if (Region && memspace::isMemSpaceOrTrait<StackSpaceRegion>(State, Region))
Regions.push_back(Region);
}
return Regions;
@@ -212,7 +214,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
void StackAddrEscapeChecker::checkReturnedBlockCaptures(
const BlockDataRegion &B, CheckerContext &C) const {
for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
- if (isNotInCurrentFrame(Region, C))
+ if (isNotInCurrentFrame(Region->getMemorySpace(), C))
continue;
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
@@ -265,7 +267,14 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
checkReturnedBlockCaptures(*B, C);
- if (!isa<StackSpaceRegion>(R->getMemorySpace()) || isNotInCurrentFrame(R, C))
+ if (isa<UnknownSpaceRegion>(R)) {
+ const MemSpaceRegion *MS = memspace::getMemSpaceTrait(C.getState(), R);
+ if (!isa_and_nonnull<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
+ return;
+ }
+
+ const MemSpaceRegion *MS = R->getMemorySpace();
+ if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
return;
// Returning a record by value is fine. (In this case, the returned
@@ -468,7 +477,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
if (!isa_and_nonnull<GlobalsSpaceRegion>(
getStackOrGlobalSpaceRegion(Region)))
return true;
- if (VR && VR->hasStackStorage() && !isNotInCurrentFrame(VR, Ctx))
+ if (VR && VR->hasStackStorage() &&
+ !isNotInCurrentFrame(VR->getMemorySpace(), Ctx))
V.emplace_back(Region, VR);
return true;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index da2d16ca9b5dd7..1c6c5fa14bceec 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
@@ -411,7 +412,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
// because that's likely to be bad news.
ProgramStateRef state = C.getState();
const MemRegion *R = Call.getArgSVal(0).getAsRegion();
- if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+ if (!R || !memspace::isMemSpaceOrTrait<StackSpaceRegion>(state, R))
return;
ExplodedNode *N = C.generateErrorNode(state);
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index a9b4dbb39b5bd6..e708bd8ec2f72d 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -40,6 +40,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
@@ -1193,7 +1194,16 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
return false;
const MemSpaceRegion *VarSpace = VR->getMemorySpace();
- const auto *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
+ const StackSpaceRegion *FrameSpace;
+
+ if (isa<UnknownSpaceRegion>(VarSpace)) {
+ ProgramStateRef State = N->getState();
+ const MemSpaceRegion *MemSpace = memspace::getMemSpaceTrait(State, VR);
+ FrameSpace = dyn_cast_if_present<StackSpaceRegion>(MemSpace);
+ } else {
+ FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
+ }
+
if (!FrameSpace) {
// If we ever directly evaluate global DeclStmts, this assertion will be
// invalid, but this still seems preferable to silently accepting an
diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
index fb9394a519eb71..993d37bb052e9b 100644
--- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -36,6 +36,7 @@ add_clang_library(clangStaticAnalyzerCore
LoopUnrolling.cpp
LoopWidening.cpp
MemRegion.cpp
+ MemSpaces.cpp
PlistDiagnostics.cpp
ProgramState.cpp
RangeConstraintManager.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 70e95c2c644c09..f22d4e7bf9dbd0 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -53,6 +53,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
@@ -3516,6 +3517,15 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
continue;
}
+ // Case (2) continued.
+ if (isa<UnknownSpaceRegion>(MR)) {
+ const MemSpaceRegion *MS = memspace::getMemSpaceTrait(State, MR);
+ if (!isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MS)) {
+ Escaped.push_back(LocAndVal.second);
+ continue;
+ }
+ }
+
// Case (3).
if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
new file mode 100644
index 00000000000000..909d11d6456758
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -0,0 +1,62 @@
+//===-- MemSpaces.cpp ---------------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include <cassert>
+
+REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
+ const clang::ento::MemSpaceRegion *)
+
+namespace clang {
+namespace ento {
+namespace memspace {
+
+ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
+ const MemSpaceRegion *MS) {
+ // for now, this should only be called to update the trait for mem regions
+ // that have an unknown mem spaces since we assume everywhere else that the
+ // memspace trait is set only for unknown mem spaces (setting this info
+ // otherwise would go unused).
+ assert(isa<UnknownSpaceRegion>(MR->getMemorySpace()));
+
+ // Shouldn't use the memspace trait to associate UnknownSpaceRegion with an
+ // already UnknownSpaceRegion
+ assert(!isa<UnknownSpaceRegion>(MS));
+
+ ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
+ return NewState;
+}
+
+bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
+ if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
+ return false;
+
+ const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
+ return Result;
+}
+
+const MemSpaceRegion *getMemSpaceTrait(ProgramStateRef State,
+ const MemRegion *MR) {
+ if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
+ return nullptr;
+
+ const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
+ if (!Result)
+ return nullptr;
+ return *Result;
+}
+
+} // namespace memspace
+} // namespace ento
+} // namespace clang
>From 94c0e4da693faeacb108e3dc239ed56d99242b3c Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 09:13:10 -0600
Subject: [PATCH 02/21] Uppercase start and s/mem/memory/ in long comment
---
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 909d11d6456758..886359fdbfab3d 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -24,13 +24,13 @@ namespace memspace {
ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
const MemSpaceRegion *MS) {
- // for now, this should only be called to update the trait for mem regions
- // that have an unknown mem spaces since we assume everywhere else that the
- // memspace trait is set only for unknown mem spaces (setting this info
+ // For now, this should only be called to update the trait for memory regions
+ // that have an unknown memory spaces since we assume everywhere else that the
+ // memory space trait is set only for unknown memory spaces (setting this info
// otherwise would go unused).
assert(isa<UnknownSpaceRegion>(MR->getMemorySpace()));
- // Shouldn't use the memspace trait to associate UnknownSpaceRegion with an
+ // Shouldn't use the memory space trait to associate UnknownSpaceRegion with an
// already UnknownSpaceRegion
assert(!isa<UnknownSpaceRegion>(MS));
>From 79a7c900303b84164aa8b473f0e241e44a80062b Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 09:22:54 -0600
Subject: [PATCH 03/21] Fill in TODO file headers description and format
comments
---
.../clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h | 7 ++++++-
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 8 +++++---
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 178a6b60c1cb1a..4f03738254b936 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -6,7 +6,12 @@
//
//===----------------------------------------------------------------------===//
//
-// TODO
+// This file declares getters and setters for the memory space trait which
+// associates memory regions with memory spaces in the program state. We are
+// still transitioning to having all memory space information stored in the
+// trait, so currently memory regions still have memory spaces as a class field.
+// Because of this, these getters still consider memory spaces set as class
+// fields in memory region types.
//
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 886359fdbfab3d..47ad03c04b2ece 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -6,7 +6,9 @@
//
//===----------------------------------------------------------------------===//
//
-// TODO
+// This file defines getters and setters for the memory space trait which
+// associates memory regions with memory spaces in the program state. It also
+// defines the MemSpacesMap which maps memory regions to memory spaces.
//
//===----------------------------------------------------------------------===//
@@ -30,8 +32,8 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
// otherwise would go unused).
assert(isa<UnknownSpaceRegion>(MR->getMemorySpace()));
- // Shouldn't use the memory space trait to associate UnknownSpaceRegion with an
- // already UnknownSpaceRegion
+ // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
+ // an already UnknownSpaceRegion
assert(!isa<UnknownSpaceRegion>(MS));
ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
>From bcc2f937bcc22d98ee06ebea9e3944fc16089997 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 11:33:52 -0600
Subject: [PATCH 04/21] getMemSpaceTrait->getMemSpace
---
.../StaticAnalyzer/Core/PathSensitive/MemSpaces.h | 4 ++--
clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 4 ++--
.../Checkers/PutenvStackArrayChecker.cpp | 2 +-
.../RetainCountChecker/RetainCountDiagnostics.cpp | 2 +-
.../Checkers/StackAddrEscapeChecker.cpp | 2 +-
.../lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 12 +++++-------
8 files changed, 14 insertions(+), 16 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 4f03738254b936..b6ca1f9e4ab78e 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -33,7 +33,7 @@ namespace memspace {
const MemRegion *MR,
const MemSpaceRegion *MS);
-[[nodiscard]] const MemSpaceRegion *getMemSpaceTrait(ProgramStateRef State,
+[[nodiscard]] const MemSpaceRegion *getMemSpace(ProgramStateRef State,
const MemRegion *MR);
[[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
@@ -42,7 +42,7 @@ template <typename FirstT, typename... RestT>
[[nodiscard]] bool isMemSpaceOrTrait(ProgramStateRef State,
const MemRegion *MR) {
return isa<FirstT, RestT...>(MR->getMemorySpace()) ||
- isa_and_nonnull<FirstT, RestT...>(getMemSpaceTrait(State, MR));
+ isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
}
} // namespace memspace
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 76fee2f1322e17..7d13e82472d7bd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2213,7 +2213,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
// - The region has unknown memspace and no trait for further clarification
// (i.e., just unknown)
// - The region has unknown memspace and a heap memspace trait
- const MemSpaceRegion *MSTrait = memspace::getMemSpaceTrait(State, R);
+ const MemSpaceRegion *MSTrait = memspace::getMemSpace(State, R);
bool HasHeapOrUnknownTrait = !MSTrait || isa<HeapSpaceRegion>(MSTrait);
if (!(isa<HeapSpaceRegion>(MS) ||
(isa<UnknownSpaceRegion>(MS) && HasHeapOrUnknownTrait))) {
@@ -2414,7 +2414,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
return true;
default: {
const MemSpaceRegion *MS = MR->getMemorySpace();
- const MemSpaceRegion *MSTrait = memspace::getMemSpaceTrait(State, MR);
+ const MemSpaceRegion *MSTrait = memspace::getMemSpace(State, MR);
if (isa<StackLocalsSpaceRegion>(MS) ||
isa_and_nonnull<StackLocalsSpaceRegion>(MSTrait)) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 4449cb4ae68eb9..fddef2ee0ac161 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -51,7 +51,7 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
const auto *SSR = dyn_cast<StackSpaceRegion>(MR->getMemorySpace());
if (!SSR)
SSR = dyn_cast_if_present<StackSpaceRegion>(
- memspace::getMemSpaceTrait(C.getState(), MR));
+ memspace::getMemSpace(C.getState(), MR));
if (!SSR)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index ecc7563ceb4bba..80fa8d3e3f921e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -695,7 +695,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
dyn_cast<StackSpaceRegion>(R->getMemorySpace());
if (!MR)
MR = dyn_cast_if_present<StackSpaceRegion>(
- memspace::getMemSpaceTrait(St, R));
+ memspace::getMemSpace(St, R));
if (MR && MR->getStackFrame() == LeakContext->getStackFrame())
FirstBinding = R;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 4d8c8eea14ea63..43a444e3b8ee84 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -268,7 +268,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
checkReturnedBlockCaptures(*B, C);
if (isa<UnknownSpaceRegion>(R)) {
- const MemSpaceRegion *MS = memspace::getMemSpaceTrait(C.getState(), R);
+ const MemSpaceRegion *MS = memspace::getMemSpace(C.getState(), R);
if (!isa_and_nonnull<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
return;
}
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index e708bd8ec2f72d..ad2429d61de927 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1198,7 +1198,7 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
if (isa<UnknownSpaceRegion>(VarSpace)) {
ProgramStateRef State = N->getState();
- const MemSpaceRegion *MemSpace = memspace::getMemSpaceTrait(State, VR);
+ const MemSpaceRegion *MemSpace = memspace::getMemSpace(State, VR);
FrameSpace = dyn_cast_if_present<StackSpaceRegion>(MemSpace);
} else {
FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index f22d4e7bf9dbd0..82274f3327f16d 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3519,7 +3519,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
// Case (2) continued.
if (isa<UnknownSpaceRegion>(MR)) {
- const MemSpaceRegion *MS = memspace::getMemSpaceTrait(State, MR);
+ const MemSpaceRegion *MS = memspace::getMemSpace(State, MR);
if (!isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MS)) {
Escaped.push_back(LocAndVal.second);
continue;
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 47ad03c04b2ece..1dd6568cfa80d2 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -48,15 +48,13 @@ bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
return Result;
}
-const MemSpaceRegion *getMemSpaceTrait(ProgramStateRef State,
+const MemSpaceRegion *getMemSpace(ProgramStateRef State,
const MemRegion *MR) {
- if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
- return nullptr;
-
const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
- if (!Result)
- return nullptr;
- return *Result;
+ if (Result)
+ return *Result;
+
+ return MR->getMemorySpace();
}
} // namespace memspace
>From 28bc5a3009236f3d50a9db9f7580ffd295a2e31c Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 11:49:27 -0600
Subject: [PATCH 05/21] add comment about invariant
---
.../Core/PathSensitive/MemSpaces.h | 2 +-
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 22 ++++++++++++++++++-
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index b6ca1f9e4ab78e..0f8f72fd6993fb 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -34,7 +34,7 @@ namespace memspace {
const MemSpaceRegion *MS);
[[nodiscard]] const MemSpaceRegion *getMemSpace(ProgramStateRef State,
- const MemRegion *MR);
+ const MemRegion *MR);
[[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 1dd6568cfa80d2..28749364982545 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -9,6 +9,14 @@
// This file defines getters and setters for the memory space trait which
// associates memory regions with memory spaces in the program state. It also
// defines the MemSpacesMap which maps memory regions to memory spaces.
+//
+// These functions keep the following invariants over the MemSpacesMap:
+// 1. (Temporary as an intermediate step) Memory space traits are only
+// mapped for memory regions that have an unknown memory space
+// 2. Only base memory regions are mapped in the trait
+// 3. Memory regions which have no mapping in the trait are assumed to be
+// unknown; no memory region is allowed to be mapped to an unknown memory
+// space in the trait;
//
//===----------------------------------------------------------------------===//
@@ -24,8 +32,16 @@ namespace clang {
namespace ento {
namespace memspace {
+// Canonicalize to base, in case of subregions, we don't want base regions and subregions
+// to have different memory spaces
+[[nodiscard]] static const MemRegion *canonicalizeMemRegion(const MemRegion *MR) {
+ return MR->getBaseRegion();
+}
+
ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
const MemSpaceRegion *MS) {
+ MR = canonicalizeMemRegion(MR);
+
// For now, this should only be called to update the trait for memory regions
// that have an unknown memory spaces since we assume everywhere else that the
// memory space trait is set only for unknown memory spaces (setting this info
@@ -41,6 +57,8 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
}
bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
+ MR = canonicalizeMemRegion(MR);
+
if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
return false;
@@ -49,7 +67,9 @@ bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
}
const MemSpaceRegion *getMemSpace(ProgramStateRef State,
- const MemRegion *MR) {
+ const MemRegion *MR) {
+ MR = canonicalizeMemRegion(MR);
+
const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
if (Result)
return *Result;
>From c6482c4327fd21de71e3e9591137b49e6f055eb0 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 12:00:06 -0600
Subject: [PATCH 06/21] isMemSpaceOrTrait->isMemSpace
---
.../clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h | 4 ++--
clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | 4 ++--
clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp | 2 +-
clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp | 2 +-
clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp | 2 +-
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 0f8f72fd6993fb..132261391c2716 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -39,8 +39,8 @@ namespace memspace {
[[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
template <typename FirstT, typename... RestT>
-[[nodiscard]] bool isMemSpaceOrTrait(ProgramStateRef State,
- const MemRegion *MR) {
+[[nodiscard]] bool isMemSpace(ProgramStateRef State,
+ const MemRegion *MR) {
return isa<FirstT, RestT...>(MR->getMemorySpace()) ||
isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 858b6a37551f5d..c81f1bfa7eaf32 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -80,7 +80,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
// Global variables are fine.
const MemRegion *RB = R->getBaseRegion();
- if (memspace::isMemSpaceOrTrait<GlobalsSpaceRegion>(State, RB))
+ if (memspace::isMemSpace<GlobalsSpaceRegion>(State, RB))
return;
// Handle _dispatch_once. In some versions of the OS X SDK we have the case
@@ -119,7 +119,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (IVR != R)
os << " memory within";
os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
- } else if (memspace::isMemSpaceOrTrait<HeapSpaceRegion>(State, RB)) {
+ } else if (memspace::isMemSpace<HeapSpaceRegion>(State, RB)) {
os << " heap-allocated memory";
} else if (isa<UnknownSpaceRegion>(RB->getMemorySpace())) {
// Presence of an IVar superregion has priority over this branch, because
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index d4ff8186ea69c9..042c4e0c1ab2e6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -561,7 +561,7 @@ MoveChecker::classifyObject(ProgramStateRef State, const MemRegion *MR,
MR = unwrapRValueReferenceIndirection(MR);
bool IsLocal =
isa_and_nonnull<VarRegion, CXXLifetimeExtendedObjectRegion>(MR) &&
- memspace::isMemSpaceOrTrait<StackSpaceRegion>(State, MR);
+ memspace::isMemSpace<StackSpaceRegion>(State, MR);
if (!RD || !RD->getDeclContext()->isStdNamespace())
return { IsLocal, SK_NonStd };
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 43a444e3b8ee84..9f126cd8d3d23c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -143,7 +143,7 @@ StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
for (auto Var : B.referenced_vars()) {
SVal Val = State->getSVal(Var.getCapturedRegion());
const MemRegion *Region = Val.getAsRegion();
- if (Region && memspace::isMemSpaceOrTrait<StackSpaceRegion>(State, Region))
+ if (Region && memspace::isMemSpace<StackSpaceRegion>(State, Region))
Regions.push_back(Region);
}
return Regions;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 1c6c5fa14bceec..0da562a9fe51db 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -412,7 +412,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
// because that's likely to be bad news.
ProgramStateRef state = C.getState();
const MemRegion *R = Call.getArgSVal(0).getAsRegion();
- if (!R || !memspace::isMemSpaceOrTrait<StackSpaceRegion>(state, R))
+ if (!R || !memspace::isMemSpace<StackSpaceRegion>(state, R))
return;
ExplodedNode *N = C.generateErrorNode(state);
>From 4dd1432f15428fb05f46f8fc56c2c9d583c80809 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 12:59:00 -0600
Subject: [PATCH 07/21] change MacOSXApiChecker and MallocChecker
---
.../Core/PathSensitive/MemSpaces.h | 5 +----
.../Checkers/MacOSXAPIChecker.cpp | 2 +-
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 21 +++++--------------
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 10 ---------
4 files changed, 7 insertions(+), 31 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 132261391c2716..419d24ac58ef6d 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -36,13 +36,10 @@ namespace memspace {
[[nodiscard]] const MemSpaceRegion *getMemSpace(ProgramStateRef State,
const MemRegion *MR);
-[[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
-
template <typename FirstT, typename... RestT>
[[nodiscard]] bool isMemSpace(ProgramStateRef State,
const MemRegion *MR) {
- return isa<FirstT, RestT...>(MR->getMemorySpace()) ||
- isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
+ return isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
}
} // namespace memspace
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index c81f1bfa7eaf32..e8d68e27fdaff3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -121,7 +121,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
} else if (memspace::isMemSpace<HeapSpaceRegion>(State, RB)) {
os << " heap-allocated memory";
- } else if (isa<UnknownSpaceRegion>(RB->getMemorySpace())) {
+ } else if (memspace::isMemSpace<UnknownSpaceRegion>(State, RB)) {
// Presence of an IVar superregion has priority over this branch, because
// ObjC objects are on the heap even if the core doesn't realize this.
// Presence of a block variable base region has priority over this branch,
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 7d13e82472d7bd..7d127facd1a36a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2204,8 +2204,6 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
return nullptr;
}
- const MemSpaceRegion *MS = R->getMemorySpace();
-
// Parameters, locals, statics, globals, and memory returned by
// __builtin_alloca() shouldn't be freed.
// Should skip this check if:
@@ -2213,16 +2211,13 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
// - The region has unknown memspace and no trait for further clarification
// (i.e., just unknown)
// - The region has unknown memspace and a heap memspace trait
- const MemSpaceRegion *MSTrait = memspace::getMemSpace(State, R);
- bool HasHeapOrUnknownTrait = !MSTrait || isa<HeapSpaceRegion>(MSTrait);
- if (!(isa<HeapSpaceRegion>(MS) ||
- (isa<UnknownSpaceRegion>(MS) && HasHeapOrUnknownTrait))) {
+ if (!memspace::isMemSpace<HeapSpaceRegion, UnknownSpaceRegion>(State, R)) {
// Regions returned by malloc() are represented by SymbolicRegion objects
// within HeapSpaceRegion. Of course, free() can work on memory allocated
// outside the current function, so UnknownSpaceRegion is also a
// possibility here.
- if (isa<AllocaRegion>(R) || isa_and_nonnull<AllocaRegion>(MSTrait))
+ if (isa<AllocaRegion>(R))
HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
else
HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
@@ -2413,11 +2408,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
os << "a block";
return true;
default: {
- const MemSpaceRegion *MS = MR->getMemorySpace();
- const MemSpaceRegion *MSTrait = memspace::getMemSpace(State, MR);
-
- if (isa<StackLocalsSpaceRegion>(MS) ||
- isa_and_nonnull<StackLocalsSpaceRegion>(MSTrait)) {
+ if (memspace::isMemSpace<StackLocalsSpaceRegion>(State, MR)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -2432,8 +2423,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
return true;
}
- if (isa<StackArgumentsSpaceRegion>(MS) ||
- isa_and_nonnull<StackArgumentsSpaceRegion>(MSTrait)) {
+ if (memspace::isMemSpace<StackArgumentsSpaceRegion>(State, MR)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -2448,8 +2438,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
return true;
}
- if (isa<GlobalsSpaceRegion>(MS) ||
- isa_and_nonnull<GlobalsSpaceRegion>(MSTrait)) {
+ if (memspace::isMemSpace<GlobalsSpaceRegion>(State, MR)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 28749364982545..e20c1d15e4c518 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -56,16 +56,6 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
return NewState;
}
-bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
- MR = canonicalizeMemRegion(MR);
-
- if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
- return false;
-
- const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
- return Result;
-}
-
const MemSpaceRegion *getMemSpace(ProgramStateRef State,
const MemRegion *MR) {
MR = canonicalizeMemRegion(MR);
>From 2f2730b0d6c634c732358e9fa081f86c3c5d36ef Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:21:31 -0600
Subject: [PATCH 08/21] PutenvStackArrayChecker converted
---
.../lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index fddef2ee0ac161..455cb6cc37a1fe 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -48,10 +48,7 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
const MemRegion *MR = ArgV.getAsRegion();
- const auto *SSR = dyn_cast<StackSpaceRegion>(MR->getMemorySpace());
- if (!SSR)
- SSR = dyn_cast_if_present<StackSpaceRegion>(
- memspace::getMemSpace(C.getState(), MR));
+ const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(C.getState(), MR));
if (!SSR)
return;
>From 7f7c274078a90d67299c7144257c32928b2d96da Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:21:45 -0600
Subject: [PATCH 09/21] ExprEngine
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 82274f3327f16d..1a056d8fc5970c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3518,12 +3518,9 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
}
// Case (2) continued.
- if (isa<UnknownSpaceRegion>(MR)) {
- const MemSpaceRegion *MS = memspace::getMemSpace(State, MR);
- if (!isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MS)) {
- Escaped.push_back(LocAndVal.second);
- continue;
- }
+ if (memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State, MR)) {
+ Escaped.push_back(LocAndVal.second);
+ continue;
}
// Case (3).
>From 8fb29b7644c0ed25d6b5ce92bcee21e92fe6c34f Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:21:58 -0600
Subject: [PATCH 10/21] BugReporterVisitors
---
.../lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index ad2429d61de927..458d3e545ccd2f 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1194,16 +1194,8 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
return false;
const MemSpaceRegion *VarSpace = VR->getMemorySpace();
- const StackSpaceRegion *FrameSpace;
-
- if (isa<UnknownSpaceRegion>(VarSpace)) {
- ProgramStateRef State = N->getState();
- const MemSpaceRegion *MemSpace = memspace::getMemSpace(State, VR);
- FrameSpace = dyn_cast_if_present<StackSpaceRegion>(MemSpace);
- } else {
- FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
- }
-
+ const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(N->getState(), VR));
+
if (!FrameSpace) {
// If we ever directly evaluate global DeclStmts, this assertion will be
// invalid, but this still seems preferable to silently accepting an
>From 5503e7ad396a94a64e11f371d88fb7caedfd9230 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:22:12 -0600
Subject: [PATCH 11/21] StackAddrEscapeChecker
---
.../StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 9f126cd8d3d23c..25323b6bea3d4d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -267,13 +267,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
checkReturnedBlockCaptures(*B, C);
- if (isa<UnknownSpaceRegion>(R)) {
- const MemSpaceRegion *MS = memspace::getMemSpace(C.getState(), R);
- if (!isa_and_nonnull<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
- return;
- }
-
- const MemSpaceRegion *MS = R->getMemorySpace();
+ const MemSpaceRegion *MS = memspace::getMemSpace(C.getState(), R);
if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
return;
>From a51d7576945d539483c8b17feefba3d8c34fa767 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:22:26 -0600
Subject: [PATCH 12/21] RetainCountDiagnostics
---
.../RetainCountChecker/RetainCountDiagnostics.cpp | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 80fa8d3e3f921e..0d4a102538a6d1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -691,13 +691,9 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
const MemRegion *R = FB.getRegion();
// Do not show local variables belonging to a function other than
// where the error is reported.
- const StackSpaceRegion *MR =
- dyn_cast<StackSpaceRegion>(R->getMemorySpace());
- if (!MR)
- MR = dyn_cast_if_present<StackSpaceRegion>(
- memspace::getMemSpace(St, R));
+ const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(St, R));
- if (MR && MR->getStackFrame() == LeakContext->getStackFrame())
+ if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
FirstBinding = R;
}
>From c67671e27d593147691fa9f7ffdd71f131b19a32 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:52:02 -0600
Subject: [PATCH 13/21] ExprEngine remove redundant added case, invert
condition bugfix
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 1a056d8fc5970c..7a9177b3bcc770 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3512,13 +3512,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
// Cases (1) and (2).
const MemRegion *MR = LocAndVal.first.getAsRegion();
if (!MR ||
- !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MR->getMemorySpace())) {
- Escaped.push_back(LocAndVal.second);
- continue;
- }
-
- // Case (2) continued.
- if (memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State, MR)) {
+ !memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State, MR)) {
Escaped.push_back(LocAndVal.second);
continue;
}
>From 80b9b62e068aed8f53214086432e2e45b92981e0 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 14:02:55 -0600
Subject: [PATCH 14/21] formatting
---
.../StaticAnalyzer/Core/PathSensitive/MemSpaces.h | 3 +--
.../Checkers/PutenvStackArrayChecker.cpp | 3 ++-
.../RetainCountChecker/RetainCountDiagnostics.cpp | 3 ++-
.../lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 5 +++--
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 4 ++--
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 12 ++++++------
6 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 419d24ac58ef6d..8d6679545a8266 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -37,8 +37,7 @@ namespace memspace {
const MemRegion *MR);
template <typename FirstT, typename... RestT>
-[[nodiscard]] bool isMemSpace(ProgramStateRef State,
- const MemRegion *MR) {
+[[nodiscard]] bool isMemSpace(ProgramStateRef State, const MemRegion *MR) {
return isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 455cb6cc37a1fe..a200f54a97b8c6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -48,7 +48,8 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
const MemRegion *MR = ArgV.getAsRegion();
- const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(C.getState(), MR));
+ const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(
+ memspace::getMemSpace(C.getState(), MR));
if (!SSR)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 0d4a102538a6d1..b3a3aeac3a99e8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -691,7 +691,8 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
const MemRegion *R = FB.getRegion();
// Do not show local variables belonging to a function other than
// where the error is reported.
- const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(St, R));
+ const StackSpaceRegion *SSR =
+ dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(St, R));
if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
FirstBinding = R;
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 458d3e545ccd2f..83befeb99b5f28 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1194,8 +1194,9 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
return false;
const MemSpaceRegion *VarSpace = VR->getMemorySpace();
- const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(N->getState(), VR));
-
+ const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(
+ memspace::getMemSpace(N->getState(), VR));
+
if (!FrameSpace) {
// If we ever directly evaluate global DeclStmts, this assertion will be
// invalid, but this still seems preferable to silently accepting an
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 7a9177b3bcc770..eabadfddedebbb 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3511,8 +3511,8 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
// Cases (1) and (2).
const MemRegion *MR = LocAndVal.first.getAsRegion();
- if (!MR ||
- !memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State, MR)) {
+ if (!MR || !memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(
+ State, MR)) {
Escaped.push_back(LocAndVal.second);
continue;
}
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index e20c1d15e4c518..25846527264ab6 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -9,7 +9,7 @@
// This file defines getters and setters for the memory space trait which
// associates memory regions with memory spaces in the program state. It also
// defines the MemSpacesMap which maps memory regions to memory spaces.
-//
+//
// These functions keep the following invariants over the MemSpacesMap:
// 1. (Temporary as an intermediate step) Memory space traits are only
// mapped for memory regions that have an unknown memory space
@@ -32,9 +32,10 @@ namespace clang {
namespace ento {
namespace memspace {
-// Canonicalize to base, in case of subregions, we don't want base regions and subregions
-// to have different memory spaces
-[[nodiscard]] static const MemRegion *canonicalizeMemRegion(const MemRegion *MR) {
+// Canonicalize to base, in case of subregions, we don't want base regions and
+// subregions to have different memory spaces
+[[nodiscard]] static const MemRegion *
+canonicalizeMemRegion(const MemRegion *MR) {
return MR->getBaseRegion();
}
@@ -56,8 +57,7 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
return NewState;
}
-const MemSpaceRegion *getMemSpace(ProgramStateRef State,
- const MemRegion *MR) {
+const MemSpaceRegion *getMemSpace(ProgramStateRef State, const MemRegion *MR) {
MR = canonicalizeMemRegion(MR);
const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
>From 287bbd46862cfe2a5d1a3331e4f2b72ab70d32e8 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Tue, 21 Jan 2025 20:01:12 -0600
Subject: [PATCH 15/21] wip
---
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 9 +++++----
clang/lib/StaticAnalyzer/Core/SymbolManager.cpp | 2 +-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 25846527264ab6..662771623d3e23 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -60,11 +60,12 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
const MemSpaceRegion *getMemSpace(ProgramStateRef State, const MemRegion *MR) {
MR = canonicalizeMemRegion(MR);
+ const MemSpaceRegion *MS = MR->getMemorySpace();
+ if (!isa<UnknownSpaceRegion>(MS))
+ return MS;
+
const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
- if (Result)
- return *Result;
-
- return MR->getMemorySpace();
+ return Result ? *Result : MS;
}
} // namespace memspace
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 738b6a175ce6de..5126edac6a8508 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -437,7 +437,7 @@ bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
// tell if anything still refers to this region. Unlike SymbolicRegions,
// AllocaRegions don't have associated symbols, though, so we don't actually
// have a way to track their liveness.
- return isa<AllocaRegion, CXXThisRegion, MemSpaceRegion, CodeTextRegion>(MR);
+ return isa<AllocaRegion, CXXThisRegion, CodeTextRegion>(MR);
}
bool SymbolReaper::isLazilyCopiedRegion(const MemRegion *MR) const {
>From 82f450603bb9f4db180b561dc824d4a98d314730 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 12:25:41 -0600
Subject: [PATCH 16/21] Move memspace::* to MemRegion::* instance methods
---
.../StaticAnalyzer/Checkers/SValExplainer.h | 2 +-
.../Core/PathSensitive/MemRegion.h | 22 +++++++-
.../Core/PathSensitive/MemSpaces.h | 12 -----
.../Checkers/ArrayBoundCheckerV2.cpp | 4 +-
.../StaticAnalyzer/Checkers/ErrnoChecker.cpp | 2 +-
.../Checkers/MacOSXAPIChecker.cpp | 6 +--
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 8 +--
.../StaticAnalyzer/Checkers/MoveChecker.cpp | 2 +-
.../Checkers/NSErrorChecker.cpp | 2 +-
.../Checkers/PutenvStackArrayChecker.cpp | 2 +-
.../RetainCountChecker/RetainCountChecker.cpp | 2 +-
.../RetainCountDiagnostics.cpp | 2 +-
.../Checkers/StackAddrEscapeChecker.cpp | 14 ++---
.../Checkers/UnixAPIChecker.cpp | 4 +-
.../Core/BugReporterVisitors.cpp | 3 +-
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 3 +-
clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 53 +++++++++++++++----
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 35 ------------
clang/lib/StaticAnalyzer/Core/RegionStore.cpp | 8 +--
.../StaticAnalyzer/Core/SimpleSValBuilder.cpp | 4 +-
.../lib/StaticAnalyzer/Core/SymbolManager.cpp | 2 +-
21 files changed, 98 insertions(+), 94 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index 43a70f596a4da2..f07e69621404c4 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -166,7 +166,7 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
.getCanonicalType()->getAs<ObjCObjectPointerType>())
return "object at " + Visit(R->getSymbol());
// Other heap-based symbolic regions are also special.
- if (isa<HeapSpaceRegion>(R->getMemorySpace()))
+ if (isa<HeapSpaceRegion>(R->getRawMemorySpace()))
return "heap segment that starts at " + Visit(R->getSymbol());
return "pointee of " + Visit(R->getSymbol());
}
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f88bf70d72398c..f414737b6cd313 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -26,6 +26,7 @@
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "llvm/ADT/DenseMap.h"
@@ -119,7 +120,21 @@ class MemRegion : public llvm::FoldingSetNode {
virtual MemRegionManager &getMemRegionManager() const = 0;
- LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getMemorySpace() const;
+ /// Deprecated. Gets the 'raw' memory space of a memory region's base region. Deprecated
+ /// in favor of the memory space trait which maps memory regions to memory spaces, allowing
+ /// dynamic updating of a memory region's memory space.
+ /// @deprecated Use getMemorySpace(ProgramStateRef) instead.
+ LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getRawMemorySpace() const;
+
+ /// Returns the most specific memory space for this memory region in the given ProgramStateRef.
+ [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getMemorySpace(ProgramStateRef State) const;
+
+ template <typename FirstT, typename... RestT>
+ [[nodiscard]] bool isMemorySpace(ProgramStateRef State) const {
+ return isa_and_nonnull<FirstT, RestT...>(getMemorySpace(State));
+ }
+
+ [[nodiscard]] ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const;
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion *getBaseRegion() const;
@@ -140,7 +155,10 @@ class MemRegion : public llvm::FoldingSetNode {
/// It might return null.
const SymbolicRegion *getSymbolicBase() const;
- bool hasStackStorage() const;
+ /// @deprecated Use hasStackStorage(ProgramStateRef) instead.
+ bool hasRawStackStorage() const;
+
+ [[nodiscard]] bool hasStackStorage(ProgramStateRef State) const;
bool hasStackNonParametersStorage() const;
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 8d6679545a8266..c44f57da067da1 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -29,18 +29,6 @@ class MemSpaceRegion;
namespace memspace {
-[[nodiscard]] ProgramStateRef setMemSpaceTrait(ProgramStateRef State,
- const MemRegion *MR,
- const MemSpaceRegion *MS);
-
-[[nodiscard]] const MemSpaceRegion *getMemSpace(ProgramStateRef State,
- const MemRegion *MR);
-
-template <typename FirstT, typename... RestT>
-[[nodiscard]] bool isMemSpace(ProgramStateRef State, const MemRegion *MR) {
- return isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
-}
-
} // namespace memspace
} // namespace ento
} // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index e97be53fee4c7f..84d27000f059b5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -353,7 +353,7 @@ static std::string getRegionName(const SubRegion *Region) {
return "the memory returned by 'alloca'";
if (isa<SymbolicRegion>(Region) &&
- isa<HeapSpaceRegion>(Region->getMemorySpace()))
+ isa<HeapSpaceRegion>(Region->getRawMemorySpace()))
return "the heap area";
if (isa<StringRegion>(Region))
@@ -575,7 +575,7 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
StateUpdateReporter SUR(Reg, ByteOffset, E, C);
// CHECK LOWER BOUND
- const MemSpaceRegion *Space = Reg->getMemorySpace();
+ const MemSpaceRegion *Space = Reg->getRawMemorySpace();
if (!(isa<SymbolicRegion>(Reg) && isa<UnknownSpaceRegion>(Space))) {
// A symbolic region in unknown space represents an unknown pointer that
// may point into the middle of an array, so we don't look for underflows.
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
index beb3c8574b5fd4..c2444aaf125a1b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
@@ -231,7 +231,7 @@ ProgramStateRef ErrnoChecker::checkRegionChanges(
// Always reset errno state when the system memory space is invalidated.
// The ErrnoRegion is not always found in the list in this case.
- if (llvm::is_contained(Regions, ErrnoRegion->getMemorySpace()))
+ if (llvm::is_contained(Regions, ErrnoRegion->getRawMemorySpace()))
return clearErrnoState(State);
return State;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index e8d68e27fdaff3..14aeff31f8c80b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -80,7 +80,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
// Global variables are fine.
const MemRegion *RB = R->getBaseRegion();
- if (memspace::isMemSpace<GlobalsSpaceRegion>(State, RB))
+ if (RB->isMemorySpace<GlobalsSpaceRegion>(State))
return;
// Handle _dispatch_once. In some versions of the OS X SDK we have the case
@@ -119,9 +119,9 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (IVR != R)
os << " memory within";
os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
- } else if (memspace::isMemSpace<HeapSpaceRegion>(State, RB)) {
+ } else if (RB->isMemorySpace<HeapSpaceRegion>(State)) {
os << " heap-allocated memory";
- } else if (memspace::isMemSpace<UnknownSpaceRegion>(State, RB)) {
+ } else if (RB->isMemorySpace<UnknownSpaceRegion>(State)) {
// Presence of an IVar superregion has priority over this branch, because
// ObjC objects are on the heap even if the core doesn't realize this.
// Presence of a block variable base region has priority over this branch,
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 7d127facd1a36a..7e1f869877edd7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2211,7 +2211,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
// - The region has unknown memspace and no trait for further clarification
// (i.e., just unknown)
// - The region has unknown memspace and a heap memspace trait
- if (!memspace::isMemSpace<HeapSpaceRegion, UnknownSpaceRegion>(State, R)) {
+ if (!R->isMemorySpace<HeapSpaceRegion, UnknownSpaceRegion>(State)) {
// Regions returned by malloc() are represented by SymbolicRegion objects
// within HeapSpaceRegion. Of course, free() can work on memory allocated
// outside the current function, so UnknownSpaceRegion is also a
@@ -2408,7 +2408,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
os << "a block";
return true;
default: {
- if (memspace::isMemSpace<StackLocalsSpaceRegion>(State, MR)) {
+ if (MR->isMemorySpace<StackLocalsSpaceRegion>(State)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -2423,7 +2423,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
return true;
}
- if (memspace::isMemSpace<StackArgumentsSpaceRegion>(State, MR)) {
+ if (MR->isMemorySpace<StackArgumentsSpaceRegion>(State)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -2438,7 +2438,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
return true;
}
- if (memspace::isMemSpace<GlobalsSpaceRegion>(State, MR)) {
+ if (MR->isMemorySpace<GlobalsSpaceRegion>(State)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 042c4e0c1ab2e6..090c63c69af4fd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -561,7 +561,7 @@ MoveChecker::classifyObject(ProgramStateRef State, const MemRegion *MR,
MR = unwrapRValueReferenceIndirection(MR);
bool IsLocal =
isa_and_nonnull<VarRegion, CXXLifetimeExtendedObjectRegion>(MR) &&
- memspace::isMemSpace<StackSpaceRegion>(State, MR);
+ MR->isMemorySpace<StackSpaceRegion>(State);
if (!RD || !RD->getDeclContext()->isStdNamespace())
return { IsLocal, SK_NonStd };
diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 54870bcb4bb22b..151f6312f5d232 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -202,7 +202,7 @@ static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
const MemRegion* R = X->getRegion();
if (const VarRegion *VR = R->getAs<VarRegion>())
if (const StackArgumentsSpaceRegion *
- stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace()))
+ stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getRawMemorySpace()))
if (stackReg->getStackFrame() == SFC)
return VR->getValueType();
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index a200f54a97b8c6..f71259ee2e1c6b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -49,7 +49,7 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
const MemRegion *MR = ArgV.getAsRegion();
const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(
- memspace::getMemSpace(C.getState(), MR));
+ MR->getMemorySpace(C.getState()));
if (!SSR)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 7e74b418b33536..3887e752a43cec 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -507,7 +507,7 @@ static bool shouldEscapeRegion(const MemRegion *R) {
const auto *VR = dyn_cast<VarRegion>(R);
- if (!R->hasStackStorage() || !VR)
+ if (!R->hasRawStackStorage() || !VR)
return true;
const VarDecl *VD = VR->getDecl();
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index b3a3aeac3a99e8..ef430254b8d853 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -692,7 +692,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
// Do not show local variables belonging to a function other than
// where the error is reported.
const StackSpaceRegion *SSR =
- dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(St, R));
+ dyn_cast_if_present<StackSpaceRegion>(R->getMemSpace(St));
if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
FirstBinding = R;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 25323b6bea3d4d..903ed1d1cfa12c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -143,7 +143,7 @@ StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
for (auto Var : B.referenced_vars()) {
SVal Val = State->getSVal(Var.getCapturedRegion());
const MemRegion *Region = Val.getAsRegion();
- if (Region && memspace::isMemSpace<StackSpaceRegion>(State, Region))
+ if (Region && Region->isMemorySpace<StackSpaceRegion>(State))
Regions.push_back(Region);
}
return Regions;
@@ -214,7 +214,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
void StackAddrEscapeChecker::checkReturnedBlockCaptures(
const BlockDataRegion &B, CheckerContext &C) const {
for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
- if (isNotInCurrentFrame(Region->getMemorySpace(), C))
+ if (isNotInCurrentFrame(Region->getRawMemorySpace(), C))
continue;
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
@@ -267,7 +267,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
checkReturnedBlockCaptures(*B, C);
- const MemSpaceRegion *MS = memspace::getMemSpace(C.getState(), R);
+ const MemSpaceRegion *MS = R->getMemSpace(C.getState());
if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
return;
@@ -293,7 +293,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
static const MemSpaceRegion *getStackOrGlobalSpaceRegion(const MemRegion *R) {
assert(R);
- if (const auto *MemSpace = R->getMemorySpace()) {
+ if (const auto *MemSpace = R->getRawMemorySpace()) {
if (const auto *SSR = MemSpace->getAs<StackSpaceRegion>())
return SSR;
if (const auto *GSR = MemSpace->getAs<GlobalsSpaceRegion>())
@@ -406,7 +406,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
const MemRegion *Referred) {
const auto *ReferrerMemSpace = getStackOrGlobalSpaceRegion(Referrer);
const auto *ReferredMemSpace =
- Referred->getMemorySpace()->getAs<StackSpaceRegion>();
+ Referred->getRawMemorySpace()->getAs<StackSpaceRegion>();
if (!ReferrerMemSpace || !ReferredMemSpace)
return false;
@@ -471,8 +471,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
if (!isa_and_nonnull<GlobalsSpaceRegion>(
getStackOrGlobalSpaceRegion(Region)))
return true;
- if (VR && VR->hasStackStorage() &&
- !isNotInCurrentFrame(VR->getMemorySpace(), Ctx))
+ if (VR && VR->hasRawStackStorage() &&
+ !isNotInCurrentFrame(VR->getRawMemorySpace(), Ctx))
V.emplace_back(Region, VR);
return true;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 0da562a9fe51db..715098ecbf05d2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -412,7 +412,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
// because that's likely to be bad news.
ProgramStateRef state = C.getState();
const MemRegion *R = Call.getArgSVal(0).getAsRegion();
- if (!R || !memspace::isMemSpace<StackSpaceRegion>(state, R))
+ if (!R || !R->isMemorySpace<StackSpaceRegion>(state))
return;
ExplodedNode *N = C.generateErrorNode(state);
@@ -428,7 +428,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
os << " stack allocated memory";
os << " for the \"control\" value. Using such transient memory for "
"the control value is potentially dangerous.";
- if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
+ if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getRawMemorySpace()))
os << " Perhaps you intended to declare the variable as 'static'?";
auto report =
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 83befeb99b5f28..0df56c49ab5742 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1193,9 +1193,8 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
if (DS->getSingleDecl() != VR->getDecl())
return false;
- const MemSpaceRegion *VarSpace = VR->getMemorySpace();
const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(
- memspace::getMemSpace(N->getState(), VR));
+ VR->getMemorySpace(N->getState()));
if (!FrameSpace) {
// If we ever directly evaluate global DeclStmts, this assertion will be
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index eabadfddedebbb..23219ae291fb30 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3511,8 +3511,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
// Cases (1) and (2).
const MemRegion *MR = LocAndVal.first.getAsRegion();
- if (!MR || !memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(
- State, MR)) {
+ if (!MR || !MR->isMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
Escaped.push_back(LocAndVal.second);
continue;
}
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 559c80634c12e5..67b5117f19dc6a 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -61,6 +61,9 @@ using namespace ento;
#define DEBUG_TYPE "MemRegion"
+REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
+ const clang::ento::MemSpaceRegion *)
+
//===----------------------------------------------------------------------===//
// MemRegion Construction.
//===----------------------------------------------------------------------===//
@@ -163,20 +166,20 @@ MemRegionManager &SubRegion::getMemRegionManager() const {
}
const StackFrameContext *VarRegion::getStackFrame() const {
- const auto *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
+ const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
return SSR ? SSR->getStackFrame() : nullptr;
}
const StackFrameContext *
CXXLifetimeExtendedObjectRegion::getStackFrame() const {
- const auto *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
+ const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
return SSR ? SSR->getStackFrame() : nullptr;
}
const StackFrameContext *CXXTempObjectRegion::getStackFrame() const {
- assert(isa<StackSpaceRegion>(getMemorySpace()) &&
+ assert(isa<StackSpaceRegion>(getRawMemorySpace()) &&
"A temporary object can only be allocated on the stack");
- return cast<StackSpaceRegion>(getMemorySpace())->getStackFrame();
+ return cast<StackSpaceRegion>(getRawMemorySpace())->getStackFrame();
}
ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
@@ -1348,7 +1351,7 @@ MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt,
return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
}
-const MemSpaceRegion *MemRegion::getMemorySpace() const {
+const MemSpaceRegion *MemRegion::getRawMemorySpace() const {
const MemRegion *R = this;
const auto *SR = dyn_cast<SubRegion>(this);
@@ -1360,16 +1363,48 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const {
return cast<MemSpaceRegion>(R);
}
-bool MemRegion::hasStackStorage() const {
- return isa<StackSpaceRegion>(getMemorySpace());
+const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
+ const MemRegion *MR = getBaseRegion();
+
+ const MemSpaceRegion *MS = MR->getRawMemorySpace();
+ if (!isa<UnknownSpaceRegion>(MS))
+ return MS;
+
+ const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
+ return Result ? *Result : MS;
+}
+
+ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const {
+ const MemRegion *MR = getBaseRegion();
+
+ // For now, this should only be called to update the trait for memory regions
+ // that have an unknown memory spaces since we assume everywhere else that the
+ // memory space trait is set only for unknown memory spaces (setting this info
+ // otherwise would go unused).
+ assert(isa<UnknownSpaceRegion>(MR->getRawMemorySpace()));
+
+ // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
+ // an already UnknownSpaceRegion
+ assert(!isa<UnknownSpaceRegion>(MS));
+
+ ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
+ return NewState;
+}
+
+bool MemRegion::hasRawStackStorage() const {
+ return isa<StackSpaceRegion>(getRawMemorySpace());
+}
+
+bool MemRegion::hasStackStorage(ProgramStateRef State) const {
+ return isMemorySpace<StackSpaceRegion>(State);
}
bool MemRegion::hasStackNonParametersStorage() const {
- return isa<StackLocalsSpaceRegion>(getMemorySpace());
+ return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
}
bool MemRegion::hasStackParametersStorage() const {
- return isa<StackArgumentsSpaceRegion>(getMemorySpace());
+ return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
}
// Strips away all elements and fields.
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 662771623d3e23..7201ec816bc8a2 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -32,41 +32,6 @@ namespace clang {
namespace ento {
namespace memspace {
-// Canonicalize to base, in case of subregions, we don't want base regions and
-// subregions to have different memory spaces
-[[nodiscard]] static const MemRegion *
-canonicalizeMemRegion(const MemRegion *MR) {
- return MR->getBaseRegion();
-}
-
-ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
- const MemSpaceRegion *MS) {
- MR = canonicalizeMemRegion(MR);
-
- // For now, this should only be called to update the trait for memory regions
- // that have an unknown memory spaces since we assume everywhere else that the
- // memory space trait is set only for unknown memory spaces (setting this info
- // otherwise would go unused).
- assert(isa<UnknownSpaceRegion>(MR->getMemorySpace()));
-
- // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
- // an already UnknownSpaceRegion
- assert(!isa<UnknownSpaceRegion>(MS));
-
- ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
- return NewState;
-}
-
-const MemSpaceRegion *getMemSpace(ProgramStateRef State, const MemRegion *MR) {
- MR = canonicalizeMemRegion(MR);
-
- const MemSpaceRegion *MS = MR->getMemorySpace();
- if (!isa<UnknownSpaceRegion>(MS))
- return MS;
-
- const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
- return Result ? *Result : MS;
-}
} // namespace memspace
} // namespace ento
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index ad45ab5757a5ac..b44001f049044b 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1292,9 +1292,9 @@ bool InvalidateRegionsWorker::isInitiallyIncludedGlobalRegion(
case GFK_None:
return false;
case GFK_SystemOnly:
- return isa<GlobalSystemSpaceRegion>(R->getMemorySpace());
+ return isa<GlobalSystemSpaceRegion>(R->getRawMemorySpace());
case GFK_All:
- return isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace());
+ return isa<NonStaticGlobalSpaceRegion>(R->getRawMemorySpace());
}
llvm_unreachable("unknown globals filter");
@@ -1304,7 +1304,7 @@ bool InvalidateRegionsWorker::includeEntireMemorySpace(const MemRegion *Base) {
if (isInitiallyIncludedGlobalRegion(Base))
return true;
- const MemSpaceRegion *MemSpace = Base->getMemorySpace();
+ const MemSpaceRegion *MemSpace = Base->getRawMemorySpace();
return ITraits.hasTrait(MemSpace,
RegionAndSymbolInvalidationTraits::TK_EntireMemSpace);
}
@@ -2239,7 +2239,7 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
// Lazily derive a value for the VarRegion.
const VarDecl *VD = R->getDecl();
- const MemSpaceRegion *MS = R->getMemorySpace();
+ const MemSpaceRegion *MS = R->getRawMemorySpace();
// Arguments are always symbolic.
if (isa<StackArgumentsSpaceRegion>(MS))
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 455621739f6935..ab5b21c68f6e7f 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -948,8 +948,8 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
const MemRegion *LeftBase = LeftMR->getBaseRegion();
const MemRegion *RightBase = RightMR->getBaseRegion();
- const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace();
- const MemSpaceRegion *RightMS = RightBase->getMemorySpace();
+ const MemSpaceRegion *LeftMS = LeftBase->getRawMemorySpace();
+ const MemSpaceRegion *RightMS = RightBase->getRawMemorySpace();
const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();
// If the two regions are from different known memory spaces they cannot be
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 5126edac6a8508..738b6a175ce6de 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -437,7 +437,7 @@ bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
// tell if anything still refers to this region. Unlike SymbolicRegions,
// AllocaRegions don't have associated symbols, though, so we don't actually
// have a way to track their liveness.
- return isa<AllocaRegion, CXXThisRegion, CodeTextRegion>(MR);
+ return isa<AllocaRegion, CXXThisRegion, MemSpaceRegion, CodeTextRegion>(MR);
}
bool SymbolReaper::isLazilyCopiedRegion(const MemRegion *MR) const {
>From 1c69818ee9c0647c2c952b0d92e4af42f807db59 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 12:36:55 -0600
Subject: [PATCH 17/21] change some more MemRegion::* instace methods to raw
and non-raw
---
.../StaticAnalyzer/Core/PathSensitive/MemRegion.h | 8 ++++++--
clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 12 ++++++++++--
clang/lib/StaticAnalyzer/Core/RegionStore.cpp | 4 ++--
5 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f414737b6cd313..c889a9ab060472 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -160,9 +160,13 @@ class MemRegion : public llvm::FoldingSetNode {
[[nodiscard]] bool hasStackStorage(ProgramStateRef State) const;
- bool hasStackNonParametersStorage() const;
+ bool hasRawStackNonParametersStorage() const;
- bool hasStackParametersStorage() const;
+ [[nodiscard]] bool hasStackNonParametersStorage(ProgramStateRef State) const;
+
+ bool hasRawStackParametersStorage() const;
+
+ [[nodiscard]] bool hasStackParametersStorage(ProgramStateRef State) const;
/// Compute the offset within the top level memory object.
RegionOffset getAsOffset() const;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 9757a00f1fb2f6..470801f90adb0f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -134,7 +134,7 @@ static const ParmVarDecl *getOriginParam(SVal V, CheckerContext &C,
// routine arguments in the heap.
while (const MemRegion *MR = Sym->getOriginRegion()) {
const auto *VR = dyn_cast<VarRegion>(MR);
- if (VR && VR->hasStackParametersStorage() &&
+ if (VR && VR->hasRawStackParametersStorage() &&
VR->getStackFrame()->inTopFrame())
return cast<ParmVarDecl>(VR->getDecl());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 23219ae291fb30..0d245395665cec 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3518,7 +3518,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
// Case (3).
if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
- if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
+ if (VR->hasRawStackParametersStorage() && VR->getStackFrame()->inTopFrame())
if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
if (!RD->hasTrivialDestructor()) {
Escaped.push_back(LocAndVal.second);
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 67b5117f19dc6a..4b621e5cb4f975 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1399,14 +1399,22 @@ bool MemRegion::hasStackStorage(ProgramStateRef State) const {
return isMemorySpace<StackSpaceRegion>(State);
}
-bool MemRegion::hasStackNonParametersStorage() const {
+bool MemRegion::hasRawStackNonParametersStorage() const {
return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
}
-bool MemRegion::hasStackParametersStorage() const {
+bool MemRegion::hasStackNonParametersStorage(ProgramStateRef State) const {
+ return isMemorySpace<StackLocalsSpaceRegion>(State);
+}
+
+bool MemRegion::hasRawStackParametersStorage() const {
return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
}
+bool MemRegion::hasStackParametersStorage(ProgramStateRef State) const {
+ return isMemorySpace<StackArgumentsSpaceRegion>(State);
+}
+
// Strips away all elements and fields.
// Returns the base region of them.
const MemRegion *MemRegion::getBaseRegion() const {
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index b44001f049044b..927c8094e81aa0 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1544,7 +1544,7 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
// The location does not have a bound value. This means that it has
// the value it had upon its creation and/or entry to the analyzed
// function/method. These are either symbolic values or 'undefined'.
- if (R->hasStackNonParametersStorage()) {
+ if (R->hasRawStackNonParametersStorage()) {
// All stack variables are considered to have undefined values
// upon creation. All heap allocated blocks are considered to
// have undefined values as well unless they are explicitly bound
@@ -2175,7 +2175,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
SR = dyn_cast<SubRegion>(Base);
}
- if (R->hasStackNonParametersStorage()) {
+ if (R->hasRawStackNonParametersStorage()) {
if (isa<ElementRegion>(R)) {
// Currently we don't reason specially about Clang-style vectors. Check
// if superR is a vector and if so return Unknown.
>From 5f2053267ffef1e4fd955f19b8152d3bc57dfbce Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 12:43:47 -0600
Subject: [PATCH 18/21] remove old MemSpaces.h includes
---
.../Core/PathSensitive/MemSpaces.h | 36 -
.../Checkers/ArrayBoundCheckerV2.cpp | 1 -
.../Checkers/MacOSXAPIChecker.cpp | 1 -
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 1 -
.../StaticAnalyzer/Checkers/MoveChecker.cpp | 1 -
.../Checkers/PutenvStackArrayChecker.cpp | 1 -
.../RetainCountDiagnostics.cpp | 1 -
.../Checkers/StackAddrEscapeChecker.cpp | 1 -
.../Checkers/UnixAPIChecker.cpp | 1 -
.../Core/BugReporterVisitors.cpp | 1 -
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 -
clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 1881 -----------------
12 files changed, 1927 deletions(-)
delete mode 100644 clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
delete mode 100644 clang/lib/StaticAnalyzer/Core/MemRegion.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
deleted file mode 100644
index c44f57da067da1..00000000000000
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===-- MemSpaces.h -----------------------------------------------*- 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 declares getters and setters for the memory space trait which
-// associates memory regions with memory spaces in the program state. We are
-// still transitioning to having all memory space information stored in the
-// trait, so currently memory regions still have memory spaces as a class field.
-// Because of this, these getters still consider memory spaces set as class
-// fields in memory region types.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
-#define LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
-
-namespace clang {
-namespace ento {
-
-class MemRegion;
-class MemSpaceRegion;
-
-namespace memspace {
-
-} // namespace memspace
-} // namespace ento
-} // namespace clang
-
-#endif // LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 84d27000f059b5..3ac31cce4e46d6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -22,7 +22,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FormatVariadic.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 14aeff31f8c80b..874cc511eecb93 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -22,7 +22,6 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 7e1f869877edd7..1b1bd7be15aff6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -72,7 +72,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 090c63c69af4fd..288cbd03656abe 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -22,7 +22,6 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "llvm/ADT/StringSet.h"
using namespace clang;
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index f71259ee2e1c6b..96be9bf07e01c0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -21,7 +21,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
using namespace clang;
using namespace ento;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index ef430254b8d853..1fbfa8cf0eaddf 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -13,7 +13,6 @@
#include "RetainCountDiagnostics.h"
#include "RetainCountChecker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include <optional>
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 903ed1d1cfa12c..57f889af1e9432 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -19,7 +19,6 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 715098ecbf05d2..f62ac080c729c1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -21,7 +21,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 0df56c49ab5742..48d5be04adab52 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -40,7 +40,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 0d245395665cec..53f9998a5810a5 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -53,7 +53,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
deleted file mode 100644
index 4b621e5cb4f975..00000000000000
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ /dev/null
@@ -1,1881 +0,0 @@
-//===- MemRegion.cpp - Abstract memory regions for static analysis --------===//
-//
-// 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 MemRegion and its subclasses. MemRegion defines a
-// partially-typed abstraction of memory useful for path-sensitive dataflow
-// analyses.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/Type.h"
-#include "clang/Analysis/AnalysisDeclContext.h"
-#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CheckedArithmetic.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-#include <cstdint>
-#include <functional>
-#include <iterator>
-#include <optional>
-#include <string>
-#include <tuple>
-#include <utility>
-
-using namespace clang;
-using namespace ento;
-
-#define DEBUG_TYPE "MemRegion"
-
-REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
- const clang::ento::MemSpaceRegion *)
-
-//===----------------------------------------------------------------------===//
-// MemRegion Construction.
-//===----------------------------------------------------------------------===//
-
-[[maybe_unused]] static bool isAReferenceTypedValueRegion(const MemRegion *R) {
- const auto *TyReg = llvm::dyn_cast<TypedValueRegion>(R);
- return TyReg && TyReg->getValueType()->isReferenceType();
-}
-
-template <typename RegionTy, typename SuperTy, typename Arg1Ty>
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1,
- const SuperTy *superRegion) {
- llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, arg1, superRegion);
- void *InsertPos;
- auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
-
- if (!R) {
- R = new (A) RegionTy(arg1, superRegion);
- Regions.InsertNode(R, InsertPos);
- assert(!isAReferenceTypedValueRegion(superRegion));
- }
-
- return R;
-}
-
-template <typename RegionTy, typename SuperTy, typename Arg1Ty, typename Arg2Ty>
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
- const SuperTy *superRegion) {
- llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, arg1, arg2, superRegion);
- void *InsertPos;
- auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
-
- if (!R) {
- R = new (A) RegionTy(arg1, arg2, superRegion);
- Regions.InsertNode(R, InsertPos);
- assert(!isAReferenceTypedValueRegion(superRegion));
- }
-
- return R;
-}
-
-template <typename RegionTy, typename SuperTy,
- typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
- const Arg3Ty arg3,
- const SuperTy *superRegion) {
- llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, arg1, arg2, arg3, superRegion);
- void *InsertPos;
- auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
-
- if (!R) {
- R = new (A) RegionTy(arg1, arg2, arg3, superRegion);
- Regions.InsertNode(R, InsertPos);
- assert(!isAReferenceTypedValueRegion(superRegion));
- }
-
- return R;
-}
-
-//===----------------------------------------------------------------------===//
-// Object destruction.
-//===----------------------------------------------------------------------===//
-
-MemRegion::~MemRegion() = default;
-
-// All regions and their data are BumpPtrAllocated. No need to call their
-// destructors.
-MemRegionManager::~MemRegionManager() = default;
-
-//===----------------------------------------------------------------------===//
-// Basic methods.
-//===----------------------------------------------------------------------===//
-
-bool SubRegion::isSubRegionOf(const MemRegion* R) const {
- const MemRegion* r = this;
- do {
- if (r == R)
- return true;
- if (const auto *sr = dyn_cast<SubRegion>(r))
- r = sr->getSuperRegion();
- else
- break;
- } while (r != nullptr);
- return false;
-}
-
-MemRegionManager &SubRegion::getMemRegionManager() const {
- const SubRegion* r = this;
- do {
- const MemRegion *superRegion = r->getSuperRegion();
- if (const auto *sr = dyn_cast<SubRegion>(superRegion)) {
- r = sr;
- continue;
- }
- return superRegion->getMemRegionManager();
- } while (true);
-}
-
-const StackFrameContext *VarRegion::getStackFrame() const {
- const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
- return SSR ? SSR->getStackFrame() : nullptr;
-}
-
-const StackFrameContext *
-CXXLifetimeExtendedObjectRegion::getStackFrame() const {
- const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
- return SSR ? SSR->getStackFrame() : nullptr;
-}
-
-const StackFrameContext *CXXTempObjectRegion::getStackFrame() const {
- assert(isa<StackSpaceRegion>(getRawMemorySpace()) &&
- "A temporary object can only be allocated on the stack");
- return cast<StackSpaceRegion>(getRawMemorySpace())->getStackFrame();
-}
-
-ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
- : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {
- assert(IVD);
-}
-
-const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { return IVD; }
-
-QualType ObjCIvarRegion::getValueType() const {
- return getDecl()->getType();
-}
-
-QualType CXXBaseObjectRegion::getValueType() const {
- return QualType(getDecl()->getTypeForDecl(), 0);
-}
-
-QualType CXXDerivedObjectRegion::getValueType() const {
- return QualType(getDecl()->getTypeForDecl(), 0);
-}
-
-QualType ParamVarRegion::getValueType() const {
- assert(getDecl() &&
- "`ParamVarRegion` support functions without `Decl` not implemented"
- " yet.");
- return getDecl()->getType();
-}
-
-const ParmVarDecl *ParamVarRegion::getDecl() const {
- const Decl *D = getStackFrame()->getDecl();
-
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- assert(Index < FD->param_size());
- return FD->parameters()[Index];
- } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
- assert(Index < BD->param_size());
- return BD->parameters()[Index];
- } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- assert(Index < MD->param_size());
- return MD->parameters()[Index];
- } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
- assert(Index < CD->param_size());
- return CD->parameters()[Index];
- } else {
- llvm_unreachable("Unexpected Decl kind!");
- }
-}
-
-//===----------------------------------------------------------------------===//
-// FoldingSet profiling.
-//===----------------------------------------------------------------------===//
-
-void MemSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(static_cast<unsigned>(getKind()));
-}
-
-void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(static_cast<unsigned>(getKind()));
- ID.AddPointer(getStackFrame());
-}
-
-void StaticGlobalSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(static_cast<unsigned>(getKind()));
- ID.AddPointer(getCodeRegion());
-}
-
-void StringRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const StringLiteral *Str,
- const MemRegion *superRegion) {
- ID.AddInteger(static_cast<unsigned>(StringRegionKind));
- ID.AddPointer(Str);
- ID.AddPointer(superRegion);
-}
-
-void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const ObjCStringLiteral *Str,
- const MemRegion *superRegion) {
- ID.AddInteger(static_cast<unsigned>(ObjCStringRegionKind));
- ID.AddPointer(Str);
- ID.AddPointer(superRegion);
-}
-
-void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const Expr *Ex, unsigned cnt,
- const MemRegion *superRegion) {
- ID.AddInteger(static_cast<unsigned>(AllocaRegionKind));
- ID.AddPointer(Ex);
- ID.AddInteger(cnt);
- ID.AddPointer(superRegion);
-}
-
-void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- ProfileRegion(ID, Ex, Cnt, superRegion);
-}
-
-void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
-}
-
-void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const CompoundLiteralExpr *CL,
- const MemRegion* superRegion) {
- ID.AddInteger(static_cast<unsigned>(CompoundLiteralRegionKind));
- ID.AddPointer(CL);
- ID.AddPointer(superRegion);
-}
-
-void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const PointerType *PT,
- const MemRegion *sRegion) {
- ID.AddInteger(static_cast<unsigned>(CXXThisRegionKind));
- ID.AddPointer(PT);
- ID.AddPointer(sRegion);
-}
-
-void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
-}
-
-void FieldRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, getDecl(), superRegion);
-}
-
-void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const ObjCIvarDecl *ivd,
- const MemRegion* superRegion) {
- ID.AddInteger(static_cast<unsigned>(ObjCIvarRegionKind));
- ID.AddPointer(ivd);
- ID.AddPointer(superRegion);
-}
-
-void ObjCIvarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, getDecl(), superRegion);
-}
-
-void NonParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const VarDecl *VD,
- const MemRegion *superRegion) {
- ID.AddInteger(static_cast<unsigned>(NonParamVarRegionKind));
- ID.AddPointer(VD);
- ID.AddPointer(superRegion);
-}
-
-void NonParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, getDecl(), superRegion);
-}
-
-void ParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE,
- unsigned Idx, const MemRegion *SReg) {
- ID.AddInteger(static_cast<unsigned>(ParamVarRegionKind));
- ID.AddPointer(OE);
- ID.AddInteger(Idx);
- ID.AddPointer(SReg);
-}
-
-void ParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, getOriginExpr(), getIndex(), superRegion);
-}
-
-void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
- const MemRegion *sreg) {
- ID.AddInteger(static_cast<unsigned>(MemRegion::SymbolicRegionKind));
- ID.Add(sym);
- ID.AddPointer(sreg);
-}
-
-void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- SymbolicRegion::ProfileRegion(ID, sym, getSuperRegion());
-}
-
-void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- QualType ElementType, SVal Idx,
- const MemRegion* superRegion) {
- ID.AddInteger(MemRegion::ElementRegionKind);
- ID.Add(ElementType);
- ID.AddPointer(superRegion);
- Idx.Profile(ID);
-}
-
-void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
-}
-
-void FunctionCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const NamedDecl *FD,
- const MemRegion*) {
- ID.AddInteger(MemRegion::FunctionCodeRegionKind);
- ID.AddPointer(FD);
-}
-
-void FunctionCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- FunctionCodeRegion::ProfileRegion(ID, FD, superRegion);
-}
-
-void BlockCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const BlockDecl *BD, CanQualType,
- const AnalysisDeclContext *AC,
- const MemRegion*) {
- ID.AddInteger(MemRegion::BlockCodeRegionKind);
- ID.AddPointer(BD);
-}
-
-void BlockCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockCodeRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
-}
-
-void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const BlockCodeRegion *BC,
- const LocationContext *LC,
- unsigned BlkCount,
- const MemRegion *sReg) {
- ID.AddInteger(MemRegion::BlockDataRegionKind);
- ID.AddPointer(BC);
- ID.AddPointer(LC);
- ID.AddInteger(BlkCount);
- ID.AddPointer(sReg);
-}
-
-void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockDataRegion::ProfileRegion(ID, BC, LC, BlockCount, getSuperRegion());
-}
-
-void CXXTempObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- Expr const *Ex,
- const MemRegion *sReg) {
- ID.AddPointer(Ex);
- ID.AddPointer(sReg);
-}
-
-void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, Ex, getSuperRegion());
-}
-
-void CXXLifetimeExtendedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const Expr *E,
- const ValueDecl *D,
- const MemRegion *sReg) {
- ID.AddPointer(E);
- ID.AddPointer(D);
- ID.AddPointer(sReg);
-}
-
-void CXXLifetimeExtendedObjectRegion::Profile(
- llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, Ex, ExD, getSuperRegion());
-}
-
-void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const CXXRecordDecl *RD,
- bool IsVirtual,
- const MemRegion *SReg) {
- ID.AddPointer(RD);
- ID.AddBoolean(IsVirtual);
- ID.AddPointer(SReg);
-}
-
-void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, getDecl(), isVirtual(), superRegion);
-}
-
-void CXXDerivedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const CXXRecordDecl *RD,
- const MemRegion *SReg) {
- ID.AddPointer(RD);
- ID.AddPointer(SReg);
-}
-
-void CXXDerivedObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, getDecl(), superRegion);
-}
-
-//===----------------------------------------------------------------------===//
-// Region anchors.
-//===----------------------------------------------------------------------===//
-
-void GlobalsSpaceRegion::anchor() {}
-
-void NonStaticGlobalSpaceRegion::anchor() {}
-
-void StackSpaceRegion::anchor() {}
-
-void TypedRegion::anchor() {}
-
-void TypedValueRegion::anchor() {}
-
-void CodeTextRegion::anchor() {}
-
-void SubRegion::anchor() {}
-
-//===----------------------------------------------------------------------===//
-// Region pretty-printing.
-//===----------------------------------------------------------------------===//
-
-LLVM_DUMP_METHOD void MemRegion::dump() const {
- dumpToStream(llvm::errs());
-}
-
-std::string MemRegion::getString() const {
- std::string s;
- llvm::raw_string_ostream os(s);
- dumpToStream(os);
- return s;
-}
-
-void MemRegion::dumpToStream(raw_ostream &os) const {
- os << "<Unknown Region>";
-}
-
-void AllocaRegion::dumpToStream(raw_ostream &os) const {
- os << "alloca{S" << Ex->getID(getContext()) << ',' << Cnt << '}';
-}
-
-void FunctionCodeRegion::dumpToStream(raw_ostream &os) const {
- os << "code{" << getDecl()->getDeclName().getAsString() << '}';
-}
-
-void BlockCodeRegion::dumpToStream(raw_ostream &os) const {
- os << "block_code{" << static_cast<const void *>(this) << '}';
-}
-
-void BlockDataRegion::dumpToStream(raw_ostream &os) const {
- os << "block_data{" << BC;
- os << "; ";
- for (auto Var : referenced_vars())
- os << "(" << Var.getCapturedRegion() << "<-" << Var.getOriginalRegion()
- << ") ";
- os << '}';
-}
-
-void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const {
- // FIXME: More elaborate pretty-printing.
- os << "{ S" << CL->getID(getContext()) << " }";
-}
-
-void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
- os << "temp_object{" << getValueType() << ", "
- << "S" << Ex->getID(getContext()) << '}';
-}
-
-void CXXLifetimeExtendedObjectRegion::dumpToStream(raw_ostream &os) const {
- os << "lifetime_extended_object{" << getValueType() << ", ";
- if (const IdentifierInfo *ID = ExD->getIdentifier())
- os << ID->getName();
- else
- os << "D" << ExD->getID();
- os << ", "
- << "S" << Ex->getID(getContext()) << '}';
-}
-
-void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
- os << "Base{" << superRegion << ',' << getDecl()->getName() << '}';
-}
-
-void CXXDerivedObjectRegion::dumpToStream(raw_ostream &os) const {
- os << "Derived{" << superRegion << ',' << getDecl()->getName() << '}';
-}
-
-void CXXThisRegion::dumpToStream(raw_ostream &os) const {
- os << "this";
-}
-
-void ElementRegion::dumpToStream(raw_ostream &os) const {
- os << "Element{" << superRegion << ',' << Index << ',' << getElementType()
- << '}';
-}
-
-void FieldRegion::dumpToStream(raw_ostream &os) const {
- os << superRegion << "." << *getDecl();
-}
-
-void ObjCIvarRegion::dumpToStream(raw_ostream &os) const {
- os << "Ivar{" << superRegion << ',' << *getDecl() << '}';
-}
-
-void StringRegion::dumpToStream(raw_ostream &os) const {
- assert(Str != nullptr && "Expecting non-null StringLiteral");
- Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
-}
-
-void ObjCStringRegion::dumpToStream(raw_ostream &os) const {
- assert(Str != nullptr && "Expecting non-null ObjCStringLiteral");
- Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
-}
-
-void SymbolicRegion::dumpToStream(raw_ostream &os) const {
- if (isa<HeapSpaceRegion>(getSuperRegion()))
- os << "Heap";
- os << "SymRegion{" << sym << '}';
-}
-
-void NonParamVarRegion::dumpToStream(raw_ostream &os) const {
- if (const IdentifierInfo *ID = VD->getIdentifier())
- os << ID->getName();
- else
- os << "NonParamVarRegion{D" << VD->getID() << '}';
-}
-
-LLVM_DUMP_METHOD void RegionRawOffset::dump() const {
- dumpToStream(llvm::errs());
-}
-
-void RegionRawOffset::dumpToStream(raw_ostream &os) const {
- os << "raw_offset{" << getRegion() << ',' << getOffset().getQuantity() << '}';
-}
-
-void CodeSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "CodeSpaceRegion";
-}
-
-void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "StaticGlobalsMemSpace{" << CR << '}';
-}
-
-void GlobalInternalSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "GlobalInternalSpaceRegion";
-}
-
-void GlobalSystemSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "GlobalSystemSpaceRegion";
-}
-
-void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "GlobalImmutableSpaceRegion";
-}
-
-void HeapSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "HeapSpaceRegion";
-}
-
-void UnknownSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "UnknownSpaceRegion";
-}
-
-void StackArgumentsSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "StackArgumentsSpaceRegion";
-}
-
-void StackLocalsSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "StackLocalsSpaceRegion";
-}
-
-void ParamVarRegion::dumpToStream(raw_ostream &os) const {
- const ParmVarDecl *PVD = getDecl();
- assert(PVD &&
- "`ParamVarRegion` support functions without `Decl` not implemented"
- " yet.");
- if (const IdentifierInfo *ID = PVD->getIdentifier()) {
- os << ID->getName();
- } else {
- os << "ParamVarRegion{P" << PVD->getID() << '}';
- }
-}
-
-bool MemRegion::canPrintPretty() const {
- return canPrintPrettyAsExpr();
-}
-
-bool MemRegion::canPrintPrettyAsExpr() const {
- return false;
-}
-
-StringRef MemRegion::getKindStr() const {
- switch (getKind()) {
-#define REGION(Id, Parent) \
- case Id##Kind: \
- return #Id;
-#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
-#undef REGION
- }
- llvm_unreachable("Unkown kind!");
-}
-
-void MemRegion::printPretty(raw_ostream &os) const {
- assert(canPrintPretty() && "This region cannot be printed pretty.");
- os << "'";
- printPrettyAsExpr(os);
- os << "'";
-}
-
-void MemRegion::printPrettyAsExpr(raw_ostream &) const {
- llvm_unreachable("This region cannot be printed pretty.");
-}
-
-bool NonParamVarRegion::canPrintPrettyAsExpr() const { return true; }
-
-void NonParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
- os << getDecl()->getName();
-}
-
-bool ParamVarRegion::canPrintPrettyAsExpr() const { return true; }
-
-void ParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
- assert(getDecl() &&
- "`ParamVarRegion` support functions without `Decl` not implemented"
- " yet.");
- os << getDecl()->getName();
-}
-
-bool ObjCIvarRegion::canPrintPrettyAsExpr() const {
- return true;
-}
-
-void ObjCIvarRegion::printPrettyAsExpr(raw_ostream &os) const {
- os << getDecl()->getName();
-}
-
-bool FieldRegion::canPrintPretty() const {
- return true;
-}
-
-bool FieldRegion::canPrintPrettyAsExpr() const {
- return superRegion->canPrintPrettyAsExpr();
-}
-
-void FieldRegion::printPrettyAsExpr(raw_ostream &os) const {
- assert(canPrintPrettyAsExpr());
- superRegion->printPrettyAsExpr(os);
- os << "." << getDecl()->getName();
-}
-
-void FieldRegion::printPretty(raw_ostream &os) const {
- if (canPrintPrettyAsExpr()) {
- os << "\'";
- printPrettyAsExpr(os);
- os << "'";
- } else {
- os << "field " << "\'" << getDecl()->getName() << "'";
- }
-}
-
-bool CXXBaseObjectRegion::canPrintPrettyAsExpr() const {
- return superRegion->canPrintPrettyAsExpr();
-}
-
-void CXXBaseObjectRegion::printPrettyAsExpr(raw_ostream &os) const {
- superRegion->printPrettyAsExpr(os);
-}
-
-bool CXXDerivedObjectRegion::canPrintPrettyAsExpr() const {
- return superRegion->canPrintPrettyAsExpr();
-}
-
-void CXXDerivedObjectRegion::printPrettyAsExpr(raw_ostream &os) const {
- superRegion->printPrettyAsExpr(os);
-}
-
-std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
- std::string VariableName;
- std::string ArrayIndices;
- const MemRegion *R = this;
- SmallString<50> buf;
- llvm::raw_svector_ostream os(buf);
-
- // Enclose subject with single quotes if needed.
- auto QuoteIfNeeded = [UseQuotes](const Twine &Subject) -> std::string {
- if (UseQuotes)
- return ("'" + Subject + "'").str();
- return Subject.str();
- };
-
- // Obtain array indices to add them to the variable name.
- const ElementRegion *ER = nullptr;
- while ((ER = R->getAs<ElementRegion>())) {
- // Index is a ConcreteInt.
- if (auto CI = ER->getIndex().getAs<nonloc::ConcreteInt>()) {
- llvm::SmallString<2> Idx;
- CI->getValue()->toString(Idx);
- ArrayIndices = (llvm::Twine("[") + Idx.str() + "]" + ArrayIndices).str();
- }
- // Index is symbolic, but may have a descriptive name.
- else {
- auto SI = ER->getIndex().getAs<nonloc::SymbolVal>();
- if (!SI)
- return "";
-
- const MemRegion *OR = SI->getAsSymbol()->getOriginRegion();
- if (!OR)
- return "";
-
- std::string Idx = OR->getDescriptiveName(false);
- if (Idx.empty())
- return "";
-
- ArrayIndices = (llvm::Twine("[") + Idx + "]" + ArrayIndices).str();
- }
- R = ER->getSuperRegion();
- }
-
- // Get variable name.
- if (R) {
- // MemRegion can be pretty printed.
- if (R->canPrintPrettyAsExpr()) {
- R->printPrettyAsExpr(os);
- return QuoteIfNeeded(llvm::Twine(os.str()) + ArrayIndices);
- }
-
- // FieldRegion may have ElementRegion as SuperRegion.
- if (const auto *FR = R->getAs<FieldRegion>()) {
- std::string Super = FR->getSuperRegion()->getDescriptiveName(false);
- if (Super.empty())
- return "";
- return QuoteIfNeeded(Super + "." + FR->getDecl()->getName());
- }
- }
-
- return VariableName;
-}
-
-SourceRange MemRegion::sourceRange() const {
- // Check for more specific regions first.
- if (auto *FR = dyn_cast<FieldRegion>(this)) {
- return FR->getDecl()->getSourceRange();
- }
-
- if (auto *VR = dyn_cast<VarRegion>(this->getBaseRegion())) {
- return VR->getDecl()->getSourceRange();
- }
-
- // Return invalid source range (can be checked by client).
- return {};
-}
-
-//===----------------------------------------------------------------------===//
-// MemRegionManager methods.
-//===----------------------------------------------------------------------===//
-
-DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
- SValBuilder &SVB) const {
- const auto *SR = cast<SubRegion>(MR);
- SymbolManager &SymMgr = SVB.getSymbolManager();
-
- switch (SR->getKind()) {
- case MemRegion::AllocaRegionKind:
- case MemRegion::SymbolicRegionKind:
- return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
- case MemRegion::StringRegionKind:
- return SVB.makeIntVal(
- cast<StringRegion>(SR)->getStringLiteral()->getByteLength() + 1,
- SVB.getArrayIndexType());
- case MemRegion::CompoundLiteralRegionKind:
- case MemRegion::CXXBaseObjectRegionKind:
- case MemRegion::CXXDerivedObjectRegionKind:
- case MemRegion::CXXTempObjectRegionKind:
- case MemRegion::CXXLifetimeExtendedObjectRegionKind:
- case MemRegion::CXXThisRegionKind:
- case MemRegion::ObjCIvarRegionKind:
- case MemRegion::NonParamVarRegionKind:
- case MemRegion::ParamVarRegionKind:
- case MemRegion::ElementRegionKind:
- case MemRegion::ObjCStringRegionKind: {
- QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
- if (isa<VariableArrayType>(Ty))
- return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
-
- if (Ty->isIncompleteType())
- return UnknownVal();
-
- return getElementExtent(Ty, SVB);
- }
- case MemRegion::FieldRegionKind: {
- // Force callers to deal with bitfields explicitly.
- if (cast<FieldRegion>(SR)->getDecl()->isBitField())
- return UnknownVal();
-
- QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
- const DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB);
-
- // We currently don't model flexible array members (FAMs), which are:
- // - int array[]; of IncompleteArrayType
- // - int array[0]; of ConstantArrayType with size 0
- // - int array[1]; of ConstantArrayType with size 1
- // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
- const auto isFlexibleArrayMemberCandidate =
- [this](const ArrayType *AT) -> bool {
- if (!AT)
- return false;
-
- auto IsIncompleteArray = [](const ArrayType *AT) {
- return isa<IncompleteArrayType>(AT);
- };
- auto IsArrayOfZero = [](const ArrayType *AT) {
- const auto *CAT = dyn_cast<ConstantArrayType>(AT);
- return CAT && CAT->isZeroSize();
- };
- auto IsArrayOfOne = [](const ArrayType *AT) {
- const auto *CAT = dyn_cast<ConstantArrayType>(AT);
- return CAT && CAT->getSize() == 1;
- };
-
- using FAMKind = LangOptions::StrictFlexArraysLevelKind;
- const FAMKind StrictFlexArraysLevel =
- Ctx.getLangOpts().getStrictFlexArraysLevel();
-
- // "Default": Any trailing array member is a FAM.
- // Since we cannot tell at this point if this array is a trailing member
- // or not, let's just do the same as for "OneZeroOrIncomplete".
- if (StrictFlexArraysLevel == FAMKind::Default)
- return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);
-
- if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
- return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);
-
- if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete)
- return IsArrayOfZero(AT) || IsIncompleteArray(AT);
-
- assert(StrictFlexArraysLevel == FAMKind::IncompleteOnly);
- return IsIncompleteArray(AT);
- };
-
- if (isFlexibleArrayMemberCandidate(Ctx.getAsArrayType(Ty)))
- return UnknownVal();
-
- return Size;
- }
- // FIXME: The following are being used in 'SimpleSValBuilder' and in
- // 'ArrayBoundChecker::checkLocation' because there is no symbol to
- // represent the regions more appropriately.
- case MemRegion::BlockDataRegionKind:
- case MemRegion::BlockCodeRegionKind:
- case MemRegion::FunctionCodeRegionKind:
- return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
- default:
- llvm_unreachable("Unhandled region");
- }
-}
-
-template <typename REG>
-const REG *MemRegionManager::LazyAllocate(REG*& region) {
- if (!region) {
- region = new (A) REG(*this);
- }
-
- return region;
-}
-
-template <typename REG, typename ARG>
-const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
- if (!region) {
- region = new (A) REG(this, a);
- }
-
- return region;
-}
-
-const StackLocalsSpaceRegion*
-MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
- assert(STC);
- StackLocalsSpaceRegion *&R = StackLocalsSpaceRegions[STC];
-
- if (R)
- return R;
-
- R = new (A) StackLocalsSpaceRegion(*this, STC);
- return R;
-}
-
-const StackArgumentsSpaceRegion *
-MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
- assert(STC);
- StackArgumentsSpaceRegion *&R = StackArgumentsSpaceRegions[STC];
-
- if (R)
- return R;
-
- R = new (A) StackArgumentsSpaceRegion(*this, STC);
- return R;
-}
-
-const GlobalsSpaceRegion
-*MemRegionManager::getGlobalsRegion(MemRegion::Kind K,
- const CodeTextRegion *CR) {
- if (!CR) {
- if (K == MemRegion::GlobalSystemSpaceRegionKind)
- return LazyAllocate(SystemGlobals);
- if (K == MemRegion::GlobalImmutableSpaceRegionKind)
- return LazyAllocate(ImmutableGlobals);
- assert(K == MemRegion::GlobalInternalSpaceRegionKind);
- return LazyAllocate(InternalGlobals);
- }
-
- assert(K == MemRegion::StaticGlobalSpaceRegionKind);
- StaticGlobalSpaceRegion *&R = StaticsGlobalSpaceRegions[CR];
- if (R)
- return R;
-
- R = new (A) StaticGlobalSpaceRegion(*this, CR);
- return R;
-}
-
-const HeapSpaceRegion *MemRegionManager::getHeapRegion() {
- return LazyAllocate(heap);
-}
-
-const UnknownSpaceRegion *MemRegionManager::getUnknownRegion() {
- return LazyAllocate(unknown);
-}
-
-const CodeSpaceRegion *MemRegionManager::getCodeRegion() {
- return LazyAllocate(code);
-}
-
-//===----------------------------------------------------------------------===//
-// Constructing regions.
-//===----------------------------------------------------------------------===//
-
-const StringRegion *MemRegionManager::getStringRegion(const StringLiteral *Str){
- return getSubRegion<StringRegion>(
- Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
-}
-
-const ObjCStringRegion *
-MemRegionManager::getObjCStringRegion(const ObjCStringLiteral *Str){
- return getSubRegion<ObjCStringRegion>(
- Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
-}
-
-/// Look through a chain of LocationContexts to either find the
-/// StackFrameContext that matches a DeclContext, or find a VarRegion
-/// for a variable captured by a block.
-static llvm::PointerUnion<const StackFrameContext *, const VarRegion *>
-getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
- const DeclContext *DC,
- const VarDecl *VD) {
- while (LC) {
- if (const auto *SFC = dyn_cast<StackFrameContext>(LC)) {
- if (cast<DeclContext>(SFC->getDecl()) == DC)
- return SFC;
- }
- if (const auto *BC = dyn_cast<BlockInvocationContext>(LC)) {
- const auto *BR = static_cast<const BlockDataRegion *>(BC->getData());
- // FIXME: This can be made more efficient.
- for (auto Var : BR->referenced_vars()) {
- const TypedValueRegion *OrigR = Var.getOriginalRegion();
- if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {
- if (VR->getDecl() == VD)
- return cast<VarRegion>(Var.getCapturedRegion());
- }
- }
- }
-
- LC = LC->getParent();
- }
- return (const StackFrameContext *)nullptr;
-}
-
-const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
- const LocationContext *LC) {
- const auto *PVD = dyn_cast<ParmVarDecl>(D);
- if (PVD) {
- unsigned Index = PVD->getFunctionScopeIndex();
- const StackFrameContext *SFC = LC->getStackFrame();
- const Stmt *CallSite = SFC->getCallSite();
- if (CallSite) {
- const Decl *D = SFC->getDecl();
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (Index < FD->param_size() && FD->parameters()[Index] == PVD)
- return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
- getStackArgumentsRegion(SFC));
- } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
- if (Index < BD->param_size() && BD->parameters()[Index] == PVD)
- return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
- getStackArgumentsRegion(SFC));
- } else {
- return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
- getStackArgumentsRegion(SFC));
- }
- }
- }
-
- D = D->getCanonicalDecl();
- const MemRegion *sReg = nullptr;
-
- if (D->hasGlobalStorage() && !D->isStaticLocal()) {
- QualType Ty = D->getType();
- assert(!Ty.isNull());
- if (Ty.isConstQualified()) {
- sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
- } else if (Ctx.getSourceManager().isInSystemHeader(D->getLocation())) {
- sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
- } else {
- sReg = getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind);
- }
-
- // Finally handle static locals.
- } else {
- // FIXME: Once we implement scope handling, we will need to properly lookup
- // 'D' to the proper LocationContext.
- const DeclContext *DC = D->getDeclContext();
- llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V =
- getStackOrCaptureRegionForDeclContext(LC, DC, D);
-
- if (const auto *VR = dyn_cast_if_present<const VarRegion *>(V))
- return VR;
-
- const auto *STC = cast<const StackFrameContext *>(V);
-
- if (!STC) {
- // FIXME: Assign a more sensible memory space to static locals
- // we see from within blocks that we analyze as top-level declarations.
- sReg = getUnknownRegion();
- } else {
- if (D->hasLocalStorage()) {
- sReg =
- isa<ParmVarDecl, ImplicitParamDecl>(D)
- ? static_cast<const MemRegion *>(getStackArgumentsRegion(STC))
- : static_cast<const MemRegion *>(getStackLocalsRegion(STC));
- }
- else {
- assert(D->isStaticLocal());
- const Decl *STCD = STC->getDecl();
- if (isa<FunctionDecl, ObjCMethodDecl>(STCD))
- sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
- getFunctionCodeRegion(cast<NamedDecl>(STCD)));
- else if (const auto *BD = dyn_cast<BlockDecl>(STCD)) {
- // FIXME: The fallback type here is totally bogus -- though it should
- // never be queried, it will prevent uniquing with the real
- // BlockCodeRegion. Ideally we'd fix the AST so that we always had a
- // signature.
- QualType T;
- if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
- T = TSI->getType();
- if (T.isNull())
- T = getContext().VoidTy;
- if (!T->getAs<FunctionType>()) {
- FunctionProtoType::ExtProtoInfo Ext;
- T = getContext().getFunctionType(T, {}, Ext);
- }
- T = getContext().getBlockPointerType(T);
-
- const BlockCodeRegion *BTR =
- getBlockCodeRegion(BD, Ctx.getCanonicalType(T),
- STC->getAnalysisDeclContext());
- sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
- BTR);
- }
- else {
- sReg = getGlobalsRegion();
- }
- }
- }
- }
-
- return getNonParamVarRegion(D, sReg);
-}
-
-const NonParamVarRegion *
-MemRegionManager::getNonParamVarRegion(const VarDecl *D,
- const MemRegion *superR) {
- // Prefer the definition over the canonical decl as the canonical form.
- D = D->getCanonicalDecl();
- if (const VarDecl *Def = D->getDefinition())
- D = Def;
- return getSubRegion<NonParamVarRegion>(D, superR);
-}
-
-const ParamVarRegion *
-MemRegionManager::getParamVarRegion(const Expr *OriginExpr, unsigned Index,
- const LocationContext *LC) {
- const StackFrameContext *SFC = LC->getStackFrame();
- assert(SFC);
- return getSubRegion<ParamVarRegion>(OriginExpr, Index,
- getStackArgumentsRegion(SFC));
-}
-
-const BlockDataRegion *
-MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
- const LocationContext *LC,
- unsigned blockCount) {
- const MemSpaceRegion *sReg = nullptr;
- const BlockDecl *BD = BC->getDecl();
- if (!BD->hasCaptures()) {
- // This handles 'static' blocks.
- sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
- }
- else {
- bool IsArcManagedBlock = Ctx.getLangOpts().ObjCAutoRefCount;
-
- // ARC managed blocks can be initialized on stack or directly in heap
- // depending on the implementations. So we initialize them with
- // UnknownRegion.
- if (!IsArcManagedBlock && LC) {
- // FIXME: Once we implement scope handling, we want the parent region
- // to be the scope.
- const StackFrameContext *STC = LC->getStackFrame();
- assert(STC);
- sReg = getStackLocalsRegion(STC);
- } else {
- // We allow 'LC' to be NULL for cases where want BlockDataRegions
- // without context-sensitivity.
- sReg = getUnknownRegion();
- }
- }
-
- return getSubRegion<BlockDataRegion>(BC, LC, blockCount, sReg);
-}
-
-const CompoundLiteralRegion*
-MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
- const LocationContext *LC) {
- const MemSpaceRegion *sReg = nullptr;
-
- if (CL->isFileScope())
- sReg = getGlobalsRegion();
- else {
- const StackFrameContext *STC = LC->getStackFrame();
- assert(STC);
- sReg = getStackLocalsRegion(STC);
- }
-
- return getSubRegion<CompoundLiteralRegion>(CL, sReg);
-}
-
-const ElementRegion *
-MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
- const SubRegion *superRegion,
- const ASTContext &Ctx) {
- QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType();
-
- llvm::FoldingSetNodeID ID;
- ElementRegion::ProfileRegion(ID, T, Idx, superRegion);
-
- void *InsertPos;
- MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
- auto *R = cast_or_null<ElementRegion>(data);
-
- if (!R) {
- R = new (A) ElementRegion(T, Idx, superRegion);
- Regions.InsertNode(R, InsertPos);
- }
-
- return R;
-}
-
-const FunctionCodeRegion *
-MemRegionManager::getFunctionCodeRegion(const NamedDecl *FD) {
- // To think: should we canonicalize the declaration here?
- return getSubRegion<FunctionCodeRegion>(FD, getCodeRegion());
-}
-
-const BlockCodeRegion *
-MemRegionManager::getBlockCodeRegion(const BlockDecl *BD, CanQualType locTy,
- AnalysisDeclContext *AC) {
- return getSubRegion<BlockCodeRegion>(BD, locTy, AC, getCodeRegion());
-}
-
-const SymbolicRegion *
-MemRegionManager::getSymbolicRegion(SymbolRef sym,
- const MemSpaceRegion *MemSpace) {
- if (MemSpace == nullptr)
- MemSpace = getUnknownRegion();
- return getSubRegion<SymbolicRegion>(sym, MemSpace);
-}
-
-const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) {
- return getSubRegion<SymbolicRegion>(Sym, getHeapRegion());
-}
-
-const FieldRegion*
-MemRegionManager::getFieldRegion(const FieldDecl *d,
- const SubRegion* superRegion){
- return getSubRegion<FieldRegion>(d, superRegion);
-}
-
-const ObjCIvarRegion*
-MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl *d,
- const SubRegion* superRegion) {
- return getSubRegion<ObjCIvarRegion>(d, superRegion);
-}
-
-const CXXTempObjectRegion*
-MemRegionManager::getCXXTempObjectRegion(Expr const *E,
- LocationContext const *LC) {
- const StackFrameContext *SFC = LC->getStackFrame();
- assert(SFC);
- return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));
-}
-
-const CXXLifetimeExtendedObjectRegion *
-MemRegionManager::getCXXLifetimeExtendedObjectRegion(
- const Expr *Ex, const ValueDecl *VD, const LocationContext *LC) {
- const StackFrameContext *SFC = LC->getStackFrame();
- assert(SFC);
- return getSubRegion<CXXLifetimeExtendedObjectRegion>(
- Ex, VD, getStackLocalsRegion(SFC));
-}
-
-const CXXLifetimeExtendedObjectRegion *
-MemRegionManager::getCXXStaticLifetimeExtendedObjectRegion(
- const Expr *Ex, const ValueDecl *VD) {
- return getSubRegion<CXXLifetimeExtendedObjectRegion>(
- Ex, VD,
- getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr));
-}
-
-/// Checks whether \p BaseClass is a valid virtual or direct non-virtual base
-/// class of the type of \p Super.
-static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
- const TypedValueRegion *Super,
- bool IsVirtual) {
- BaseClass = BaseClass->getCanonicalDecl();
-
- const CXXRecordDecl *Class = Super->getValueType()->getAsCXXRecordDecl();
- if (!Class)
- return true;
-
- if (IsVirtual)
- return Class->isVirtuallyDerivedFrom(BaseClass);
-
- for (const auto &I : Class->bases()) {
- if (I.getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
- return true;
- }
-
- return false;
-}
-
-const CXXBaseObjectRegion *
-MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
- const SubRegion *Super,
- bool IsVirtual) {
- if (isa<TypedValueRegion>(Super)) {
- assert(isValidBaseClass(RD, cast<TypedValueRegion>(Super), IsVirtual));
- (void)&isValidBaseClass;
-
- if (IsVirtual) {
- // Virtual base regions should not be layered, since the layout rules
- // are different.
- while (const auto *Base = dyn_cast<CXXBaseObjectRegion>(Super))
- Super = cast<SubRegion>(Base->getSuperRegion());
- assert(Super && !isa<MemSpaceRegion>(Super));
- }
- }
-
- return getSubRegion<CXXBaseObjectRegion>(RD, IsVirtual, Super);
-}
-
-const CXXDerivedObjectRegion *
-MemRegionManager::getCXXDerivedObjectRegion(const CXXRecordDecl *RD,
- const SubRegion *Super) {
- return getSubRegion<CXXDerivedObjectRegion>(RD, Super);
-}
-
-const CXXThisRegion*
-MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
- const LocationContext *LC) {
- const auto *PT = thisPointerTy->getAs<PointerType>();
- assert(PT);
- // Inside the body of the operator() of a lambda a this expr might refer to an
- // object in one of the parent location contexts.
- const auto *D = dyn_cast<CXXMethodDecl>(LC->getDecl());
- // FIXME: when operator() of lambda is analyzed as a top level function and
- // 'this' refers to a this to the enclosing scope, there is no right region to
- // return.
- while (!LC->inTopFrame() && (!D || D->isStatic() ||
- PT != D->getThisType()->getAs<PointerType>())) {
- LC = LC->getParent();
- D = dyn_cast<CXXMethodDecl>(LC->getDecl());
- }
- const StackFrameContext *STC = LC->getStackFrame();
- assert(STC);
- return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
-}
-
-const AllocaRegion*
-MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt,
- const LocationContext *LC) {
- const StackFrameContext *STC = LC->getStackFrame();
- assert(STC);
- return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
-}
-
-const MemSpaceRegion *MemRegion::getRawMemorySpace() const {
- const MemRegion *R = this;
- const auto *SR = dyn_cast<SubRegion>(this);
-
- while (SR) {
- R = SR->getSuperRegion();
- SR = dyn_cast<SubRegion>(R);
- }
-
- return cast<MemSpaceRegion>(R);
-}
-
-const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
- const MemRegion *MR = getBaseRegion();
-
- const MemSpaceRegion *MS = MR->getRawMemorySpace();
- if (!isa<UnknownSpaceRegion>(MS))
- return MS;
-
- const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
- return Result ? *Result : MS;
-}
-
-ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const {
- const MemRegion *MR = getBaseRegion();
-
- // For now, this should only be called to update the trait for memory regions
- // that have an unknown memory spaces since we assume everywhere else that the
- // memory space trait is set only for unknown memory spaces (setting this info
- // otherwise would go unused).
- assert(isa<UnknownSpaceRegion>(MR->getRawMemorySpace()));
-
- // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
- // an already UnknownSpaceRegion
- assert(!isa<UnknownSpaceRegion>(MS));
-
- ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
- return NewState;
-}
-
-bool MemRegion::hasRawStackStorage() const {
- return isa<StackSpaceRegion>(getRawMemorySpace());
-}
-
-bool MemRegion::hasStackStorage(ProgramStateRef State) const {
- return isMemorySpace<StackSpaceRegion>(State);
-}
-
-bool MemRegion::hasRawStackNonParametersStorage() const {
- return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
-}
-
-bool MemRegion::hasStackNonParametersStorage(ProgramStateRef State) const {
- return isMemorySpace<StackLocalsSpaceRegion>(State);
-}
-
-bool MemRegion::hasRawStackParametersStorage() const {
- return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
-}
-
-bool MemRegion::hasStackParametersStorage(ProgramStateRef State) const {
- return isMemorySpace<StackArgumentsSpaceRegion>(State);
-}
-
-// Strips away all elements and fields.
-// Returns the base region of them.
-const MemRegion *MemRegion::getBaseRegion() const {
- const MemRegion *R = this;
- while (true) {
- switch (R->getKind()) {
- case MemRegion::ElementRegionKind:
- case MemRegion::FieldRegionKind:
- case MemRegion::ObjCIvarRegionKind:
- case MemRegion::CXXBaseObjectRegionKind:
- case MemRegion::CXXDerivedObjectRegionKind:
- R = cast<SubRegion>(R)->getSuperRegion();
- continue;
- default:
- break;
- }
- break;
- }
- return R;
-}
-
-// Returns the region of the root class of a C++ class hierarchy.
-const MemRegion *MemRegion::getMostDerivedObjectRegion() const {
- const MemRegion *R = this;
- while (const auto *BR = dyn_cast<CXXBaseObjectRegion>(R))
- R = BR->getSuperRegion();
- return R;
-}
-
-bool MemRegion::isSubRegionOf(const MemRegion *) const {
- return false;
-}
-
-//===----------------------------------------------------------------------===//
-// View handling.
-//===----------------------------------------------------------------------===//
-
-const MemRegion *MemRegion::StripCasts(bool StripBaseAndDerivedCasts) const {
- const MemRegion *R = this;
- while (true) {
- switch (R->getKind()) {
- case ElementRegionKind: {
- const auto *ER = cast<ElementRegion>(R);
- if (!ER->getIndex().isZeroConstant())
- return R;
- R = ER->getSuperRegion();
- break;
- }
- case CXXBaseObjectRegionKind:
- case CXXDerivedObjectRegionKind:
- if (!StripBaseAndDerivedCasts)
- return R;
- R = cast<TypedValueRegion>(R)->getSuperRegion();
- break;
- default:
- return R;
- }
- }
-}
-
-const SymbolicRegion *MemRegion::getSymbolicBase() const {
- const auto *SubR = dyn_cast<SubRegion>(this);
-
- while (SubR) {
- if (const auto *SymR = dyn_cast<SymbolicRegion>(SubR))
- return SymR;
- SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
- }
- return nullptr;
-}
-
-RegionRawOffset ElementRegion::getAsArrayOffset() const {
- int64_t offset = 0;
- const ElementRegion *ER = this;
- const MemRegion *superR = nullptr;
- ASTContext &C = getContext();
-
- // FIXME: Handle multi-dimensional arrays.
-
- while (ER) {
- superR = ER->getSuperRegion();
-
- // FIXME: generalize to symbolic offsets.
- SVal index = ER->getIndex();
- if (auto CI = index.getAs<nonloc::ConcreteInt>()) {
- // Update the offset.
- if (int64_t i = CI->getValue()->getSExtValue(); i != 0) {
- QualType elemType = ER->getElementType();
-
- // If we are pointing to an incomplete type, go no further.
- if (elemType->isIncompleteType()) {
- superR = ER;
- break;
- }
-
- int64_t size = C.getTypeSizeInChars(elemType).getQuantity();
- if (auto NewOffset = llvm::checkedMulAdd(i, size, offset)) {
- offset = *NewOffset;
- } else {
- LLVM_DEBUG(llvm::dbgs() << "MemRegion::getAsArrayOffset: "
- << "offset overflowing, returning unknown\n");
-
- return nullptr;
- }
- }
-
- // Go to the next ElementRegion (if any).
- ER = dyn_cast<ElementRegion>(superR);
- continue;
- }
-
- return nullptr;
- }
-
- assert(superR && "super region cannot be NULL");
- return RegionRawOffset(superR, CharUnits::fromQuantity(offset));
-}
-
-/// Returns true if \p Base is an immediate base class of \p Child
-static bool isImmediateBase(const CXXRecordDecl *Child,
- const CXXRecordDecl *Base) {
- assert(Child && "Child must not be null");
- // Note that we do NOT canonicalize the base class here, because
- // ASTRecordLayout doesn't either. If that leads us down the wrong path,
- // so be it; at least we won't crash.
- for (const auto &I : Child->bases()) {
- if (I.getType()->getAsCXXRecordDecl() == Base)
- return true;
- }
-
- return false;
-}
-
-static RegionOffset calculateOffset(const MemRegion *R) {
- const MemRegion *SymbolicOffsetBase = nullptr;
- int64_t Offset = 0;
-
- while (true) {
- switch (R->getKind()) {
- case MemRegion::CodeSpaceRegionKind:
- case MemRegion::StackLocalsSpaceRegionKind:
- case MemRegion::StackArgumentsSpaceRegionKind:
- case MemRegion::HeapSpaceRegionKind:
- case MemRegion::UnknownSpaceRegionKind:
- case MemRegion::StaticGlobalSpaceRegionKind:
- case MemRegion::GlobalInternalSpaceRegionKind:
- case MemRegion::GlobalSystemSpaceRegionKind:
- case MemRegion::GlobalImmutableSpaceRegionKind:
- // Stores can bind directly to a region space to set a default value.
- assert(Offset == 0 && !SymbolicOffsetBase);
- goto Finish;
-
- case MemRegion::FunctionCodeRegionKind:
- case MemRegion::BlockCodeRegionKind:
- case MemRegion::BlockDataRegionKind:
- // These will never have bindings, but may end up having values requested
- // if the user does some strange casting.
- if (Offset != 0)
- SymbolicOffsetBase = R;
- goto Finish;
-
- case MemRegion::SymbolicRegionKind:
- case MemRegion::AllocaRegionKind:
- case MemRegion::CompoundLiteralRegionKind:
- case MemRegion::CXXThisRegionKind:
- case MemRegion::StringRegionKind:
- case MemRegion::ObjCStringRegionKind:
- case MemRegion::NonParamVarRegionKind:
- case MemRegion::ParamVarRegionKind:
- case MemRegion::CXXTempObjectRegionKind:
- case MemRegion::CXXLifetimeExtendedObjectRegionKind:
- // Usual base regions.
- goto Finish;
-
- case MemRegion::ObjCIvarRegionKind:
- // This is a little strange, but it's a compromise between
- // ObjCIvarRegions having unknown compile-time offsets (when using the
- // non-fragile runtime) and yet still being distinct, non-overlapping
- // regions. Thus we treat them as "like" base regions for the purposes
- // of computing offsets.
- goto Finish;
-
- case MemRegion::CXXBaseObjectRegionKind: {
- const auto *BOR = cast<CXXBaseObjectRegion>(R);
- R = BOR->getSuperRegion();
-
- QualType Ty;
- bool RootIsSymbolic = false;
- if (const auto *TVR = dyn_cast<TypedValueRegion>(R)) {
- Ty = TVR->getDesugaredValueType(R->getContext());
- } else if (const auto *SR = dyn_cast<SymbolicRegion>(R)) {
- // If our base region is symbolic, we don't know what type it really is.
- // Pretend the type of the symbol is the true dynamic type.
- // (This will at least be self-consistent for the life of the symbol.)
- Ty = SR->getPointeeStaticType();
- RootIsSymbolic = true;
- }
-
- const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
- if (!Child) {
- // We cannot compute the offset of the base class.
- SymbolicOffsetBase = R;
- } else {
- if (RootIsSymbolic) {
- // Base layers on symbolic regions may not be type-correct.
- // Double-check the inheritance here, and revert to a symbolic offset
- // if it's invalid (e.g. due to a reinterpret_cast).
- if (BOR->isVirtual()) {
- if (!Child->isVirtuallyDerivedFrom(BOR->getDecl()))
- SymbolicOffsetBase = R;
- } else {
- if (!isImmediateBase(Child, BOR->getDecl()))
- SymbolicOffsetBase = R;
- }
- }
- }
-
- // Don't bother calculating precise offsets if we already have a
- // symbolic offset somewhere in the chain.
- if (SymbolicOffsetBase)
- continue;
-
- CharUnits BaseOffset;
- const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(Child);
- if (BOR->isVirtual())
- BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
- else
- BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
-
- // The base offset is in chars, not in bits.
- Offset += BaseOffset.getQuantity() * R->getContext().getCharWidth();
- break;
- }
-
- case MemRegion::CXXDerivedObjectRegionKind: {
- // TODO: Store the base type in the CXXDerivedObjectRegion and use it.
- goto Finish;
- }
-
- case MemRegion::ElementRegionKind: {
- const auto *ER = cast<ElementRegion>(R);
- R = ER->getSuperRegion();
-
- QualType EleTy = ER->getValueType();
- if (EleTy->isIncompleteType()) {
- // We cannot compute the offset of the base class.
- SymbolicOffsetBase = R;
- continue;
- }
-
- SVal Index = ER->getIndex();
- if (std::optional<nonloc::ConcreteInt> CI =
- Index.getAs<nonloc::ConcreteInt>()) {
- // Don't bother calculating precise offsets if we already have a
- // symbolic offset somewhere in the chain.
- if (SymbolicOffsetBase)
- continue;
-
- int64_t i = CI->getValue()->getSExtValue();
- // This type size is in bits.
- Offset += i * R->getContext().getTypeSize(EleTy);
- } else {
- // We cannot compute offset for non-concrete index.
- SymbolicOffsetBase = R;
- }
- break;
- }
- case MemRegion::FieldRegionKind: {
- const auto *FR = cast<FieldRegion>(R);
- R = FR->getSuperRegion();
- assert(R);
-
- const RecordDecl *RD = FR->getDecl()->getParent();
- if (RD->isUnion() || !RD->isCompleteDefinition()) {
- // We cannot compute offset for incomplete type.
- // For unions, we could treat everything as offset 0, but we'd rather
- // treat each field as a symbolic offset so they aren't stored on top
- // of each other, since we depend on things in typed regions actually
- // matching their types.
- SymbolicOffsetBase = R;
- }
-
- // Don't bother calculating precise offsets if we already have a
- // symbolic offset somewhere in the chain.
- if (SymbolicOffsetBase)
- continue;
-
- // Get the field number.
- unsigned idx = 0;
- for (RecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end(); FI != FE; ++FI, ++idx) {
- if (FR->getDecl() == *FI)
- break;
- }
- const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(RD);
- // This is offset in bits.
- Offset += Layout.getFieldOffset(idx);
- break;
- }
- }
- }
-
- Finish:
- if (SymbolicOffsetBase)
- return RegionOffset(SymbolicOffsetBase, RegionOffset::Symbolic);
- return RegionOffset(R, Offset);
-}
-
-RegionOffset MemRegion::getAsOffset() const {
- if (!cachedOffset)
- cachedOffset = calculateOffset(this);
- return *cachedOffset;
-}
-
-//===----------------------------------------------------------------------===//
-// BlockDataRegion
-//===----------------------------------------------------------------------===//
-
-std::pair<const VarRegion *, const VarRegion *>
-BlockDataRegion::getCaptureRegions(const VarDecl *VD) {
- MemRegionManager &MemMgr = getMemRegionManager();
- const VarRegion *VR = nullptr;
- const VarRegion *OriginalVR = nullptr;
-
- if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) {
- VR = MemMgr.getNonParamVarRegion(VD, this);
- OriginalVR = MemMgr.getVarRegion(VD, LC);
- }
- else {
- if (LC) {
- VR = MemMgr.getVarRegion(VD, LC);
- OriginalVR = VR;
- }
- else {
- VR = MemMgr.getNonParamVarRegion(VD, MemMgr.getUnknownRegion());
- OriginalVR = MemMgr.getVarRegion(VD, LC);
- }
- }
- return std::make_pair(VR, OriginalVR);
-}
-
-void BlockDataRegion::LazyInitializeReferencedVars() {
- if (ReferencedVars)
- return;
-
- AnalysisDeclContext *AC = getCodeRegion()->getAnalysisDeclContext();
- const auto &ReferencedBlockVars = AC->getReferencedBlockVars(BC->getDecl());
- auto NumBlockVars =
- std::distance(ReferencedBlockVars.begin(), ReferencedBlockVars.end());
-
- if (NumBlockVars == 0) {
- ReferencedVars = (void*) 0x1;
- return;
- }
-
- MemRegionManager &MemMgr = getMemRegionManager();
- llvm::BumpPtrAllocator &A = MemMgr.getAllocator();
- BumpVectorContext BC(A);
-
- using VarVec = BumpVector<const MemRegion *>;
-
- auto *BV = new (A) VarVec(BC, NumBlockVars);
- auto *BVOriginal = new (A) VarVec(BC, NumBlockVars);
-
- for (const auto *VD : ReferencedBlockVars) {
- const VarRegion *VR = nullptr;
- const VarRegion *OriginalVR = nullptr;
- std::tie(VR, OriginalVR) = getCaptureRegions(VD);
- assert(VR);
- assert(OriginalVR);
- BV->push_back(VR, BC);
- BVOriginal->push_back(OriginalVR, BC);
- }
-
- ReferencedVars = BV;
- OriginalVars = BVOriginal;
-}
-
-BlockDataRegion::referenced_vars_iterator
-BlockDataRegion::referenced_vars_begin() const {
- const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
-
- auto *Vec = static_cast<BumpVector<const MemRegion *> *>(ReferencedVars);
-
- if (Vec == (void*) 0x1)
- return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
-
- auto *VecOriginal =
- static_cast<BumpVector<const MemRegion *> *>(OriginalVars);
-
- return BlockDataRegion::referenced_vars_iterator(Vec->begin(),
- VecOriginal->begin());
-}
-
-BlockDataRegion::referenced_vars_iterator
-BlockDataRegion::referenced_vars_end() const {
- const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
-
- auto *Vec = static_cast<BumpVector<const MemRegion *> *>(ReferencedVars);
-
- if (Vec == (void*) 0x1)
- return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
-
- auto *VecOriginal =
- static_cast<BumpVector<const MemRegion *> *>(OriginalVars);
-
- return BlockDataRegion::referenced_vars_iterator(Vec->end(),
- VecOriginal->end());
-}
-
-llvm::iterator_range<BlockDataRegion::referenced_vars_iterator>
-BlockDataRegion::referenced_vars() const {
- return llvm::make_range(referenced_vars_begin(), referenced_vars_end());
-}
-
-const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
- for (const auto &I : referenced_vars()) {
- if (I.getCapturedRegion() == R)
- return I.getOriginalRegion();
- }
- return nullptr;
-}
-
-//===----------------------------------------------------------------------===//
-// RegionAndSymbolInvalidationTraits
-//===----------------------------------------------------------------------===//
-
-void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym,
- InvalidationKinds IK) {
- SymTraitsMap[Sym] |= IK;
-}
-
-void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
- InvalidationKinds IK) {
- assert(MR);
- if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
- setTrait(SR->getSymbol(), IK);
- else
- MRTraitsMap[MR] |= IK;
-}
-
-bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym,
- InvalidationKinds IK) const {
- const_symbol_iterator I = SymTraitsMap.find(Sym);
- if (I != SymTraitsMap.end())
- return I->second & IK;
-
- return false;
-}
-
-bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,
- InvalidationKinds IK) const {
- if (!MR)
- return false;
-
- if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
- return hasTrait(SR->getSymbol(), IK);
-
- const_region_iterator I = MRTraitsMap.find(MR);
- if (I != MRTraitsMap.end())
- return I->second & IK;
-
- return false;
-}
>From 5524964964540519d2eea20ffb4e7315694a1bfc Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 12:44:40 -0600
Subject: [PATCH 19/21] formatting
---
.../Core/PathSensitive/MemRegion.h | 19 ++++++++++++-------
.../StaticAnalyzer/Checkers/MIGChecker.cpp | 2 +-
.../Checkers/NSErrorChecker.cpp | 4 ++--
.../Checkers/PutenvStackArrayChecker.cpp | 4 ++--
.../Core/BugReporterVisitors.cpp | 4 ++--
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 6 ++++--
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 5 +----
7 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index c889a9ab060472..f81a438b407897 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -120,21 +120,26 @@ class MemRegion : public llvm::FoldingSetNode {
virtual MemRegionManager &getMemRegionManager() const = 0;
- /// Deprecated. Gets the 'raw' memory space of a memory region's base region. Deprecated
- /// in favor of the memory space trait which maps memory regions to memory spaces, allowing
- /// dynamic updating of a memory region's memory space.
+ /// Deprecated. Gets the 'raw' memory space of a memory region's base region.
+ /// Deprecated in favor of the memory space trait which maps memory regions to
+ /// memory spaces, allowing dynamic updating of a memory region's memory
+ /// space.
/// @deprecated Use getMemorySpace(ProgramStateRef) instead.
- LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getRawMemorySpace() const;
+ LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
+ getRawMemorySpace() const;
- /// Returns the most specific memory space for this memory region in the given ProgramStateRef.
- [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getMemorySpace(ProgramStateRef State) const;
+ /// Returns the most specific memory space for this memory region in the given
+ /// ProgramStateRef.
+ [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
+ getMemorySpace(ProgramStateRef State) const;
template <typename FirstT, typename... RestT>
[[nodiscard]] bool isMemorySpace(ProgramStateRef State) const {
return isa_and_nonnull<FirstT, RestT...>(getMemorySpace(State));
}
- [[nodiscard]] ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const;
+ [[nodiscard]] ProgramStateRef
+ setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const;
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion *getBaseRegion() const;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 470801f90adb0f..19f1d03ff4753a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -135,7 +135,7 @@ static const ParmVarDecl *getOriginParam(SVal V, CheckerContext &C,
while (const MemRegion *MR = Sym->getOriginRegion()) {
const auto *VR = dyn_cast<VarRegion>(MR);
if (VR && VR->hasRawStackParametersStorage() &&
- VR->getStackFrame()->inTopFrame())
+ VR->getStackFrame()->inTopFrame())
return cast<ParmVarDecl>(VR->getDecl());
const SymbolicRegion *SR = MR->getSymbolicBase();
diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 151f6312f5d232..2a4a865b16f11e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -201,8 +201,8 @@ static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
if (const VarRegion *VR = R->getAs<VarRegion>())
- if (const StackArgumentsSpaceRegion *
- stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getRawMemorySpace()))
+ if (const StackArgumentsSpaceRegion *stackReg =
+ dyn_cast<StackArgumentsSpaceRegion>(VR->getRawMemorySpace()))
if (stackReg->getStackFrame() == SFC)
return VR->getValueType();
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 96be9bf07e01c0..028f46fbd7273f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -47,8 +47,8 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
const MemRegion *MR = ArgV.getAsRegion();
- const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(
- MR->getMemorySpace(C.getState()));
+ const StackSpaceRegion *SSR =
+ dyn_cast_if_present<StackSpaceRegion>(MR->getMemorySpace(C.getState()));
if (!SSR)
return;
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 48d5be04adab52..6ef333c2bcf187 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1192,8 +1192,8 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
if (DS->getSingleDecl() != VR->getDecl())
return false;
- const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(
- VR->getMemorySpace(N->getState()));
+ const StackSpaceRegion *FrameSpace =
+ dyn_cast_if_present<StackSpaceRegion>(VR->getMemorySpace(N->getState()));
if (!FrameSpace) {
// If we ever directly evaluate global DeclStmts, this assertion will be
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 53f9998a5810a5..5a4178b4e695ec 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3510,14 +3510,16 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
// Cases (1) and (2).
const MemRegion *MR = LocAndVal.first.getAsRegion();
- if (!MR || !MR->isMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
+ if (!MR ||
+ !MR->isMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
Escaped.push_back(LocAndVal.second);
continue;
}
// Case (3).
if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
- if (VR->hasRawStackParametersStorage() && VR->getStackFrame()->inTopFrame())
+ if (VR->hasRawStackParametersStorage() &&
+ VR->getStackFrame()->inTopFrame())
if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
if (!RD->hasTrivialDestructor()) {
Escaped.push_back(LocAndVal.second);
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 7201ec816bc8a2..8221b79b0706c6 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -30,9 +30,6 @@ REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
namespace clang {
namespace ento {
-namespace memspace {
-
-
-} // namespace memspace
+namespace memspace {} // namespace memspace
} // namespace ento
} // namespace clang
>From 605cc80bc05acd094f44d2b7f918a9d13351168b Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 13:13:05 -0600
Subject: [PATCH 20/21] fix wrong file removal, more renames and comments
---
.../Core/PathSensitive/MemRegion.h | 2 +
.../RetainCountDiagnostics.cpp | 2 +-
.../Checkers/StackAddrEscapeChecker.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/CMakeLists.txt | 1 -
clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 1881 +++++++++++++++++
clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 35 -
6 files changed, 1885 insertions(+), 38 deletions(-)
create mode 100644 clang/lib/StaticAnalyzer/Core/MemRegion.cpp
delete mode 100644 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f81a438b407897..9abd5882c24548 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -165,10 +165,12 @@ class MemRegion : public llvm::FoldingSetNode {
[[nodiscard]] bool hasStackStorage(ProgramStateRef State) const;
+ /// @deprecated Use hasStackNonParametersStorage(ProgramStateRef) instead.
bool hasRawStackNonParametersStorage() const;
[[nodiscard]] bool hasStackNonParametersStorage(ProgramStateRef State) const;
+ /// @deprecated Use hasStackParametersStorage(ProgramStateRef) instead.
bool hasRawStackParametersStorage() const;
[[nodiscard]] bool hasStackParametersStorage(ProgramStateRef State) const;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 1fbfa8cf0eaddf..a5905c8d4ad473 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -691,7 +691,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
// Do not show local variables belonging to a function other than
// where the error is reported.
const StackSpaceRegion *SSR =
- dyn_cast_if_present<StackSpaceRegion>(R->getMemSpace(St));
+ dyn_cast_if_present<StackSpaceRegion>(R->getMemorySpace(St));
if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
FirstBinding = R;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 57f889af1e9432..54655c9ea15df7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -266,7 +266,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
checkReturnedBlockCaptures(*B, C);
- const MemSpaceRegion *MS = R->getMemSpace(C.getState());
+ const MemSpaceRegion *MS = R->getMemorySpace(C.getState());
if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
return;
diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
index 993d37bb052e9b..fb9394a519eb71 100644
--- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -36,7 +36,6 @@ add_clang_library(clangStaticAnalyzerCore
LoopUnrolling.cpp
LoopWidening.cpp
MemRegion.cpp
- MemSpaces.cpp
PlistDiagnostics.cpp
ProgramState.cpp
RangeConstraintManager.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
new file mode 100644
index 00000000000000..4b621e5cb4f975
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -0,0 +1,1881 @@
+//===- MemRegion.cpp - Abstract memory regions for static analysis --------===//
+//
+// 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 MemRegion and its subclasses. MemRegion defines a
+// partially-typed abstraction of memory useful for path-sensitive dataflow
+// analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CheckedArithmetic.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <utility>
+
+using namespace clang;
+using namespace ento;
+
+#define DEBUG_TYPE "MemRegion"
+
+REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
+ const clang::ento::MemSpaceRegion *)
+
+//===----------------------------------------------------------------------===//
+// MemRegion Construction.
+//===----------------------------------------------------------------------===//
+
+[[maybe_unused]] static bool isAReferenceTypedValueRegion(const MemRegion *R) {
+ const auto *TyReg = llvm::dyn_cast<TypedValueRegion>(R);
+ return TyReg && TyReg->getValueType()->isReferenceType();
+}
+
+template <typename RegionTy, typename SuperTy, typename Arg1Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1,
+ const SuperTy *superRegion) {
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, arg1, superRegion);
+ void *InsertPos;
+ auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
+
+ if (!R) {
+ R = new (A) RegionTy(arg1, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ assert(!isAReferenceTypedValueRegion(superRegion));
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename SuperTy, typename Arg1Ty, typename Arg2Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const SuperTy *superRegion) {
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, arg1, arg2, superRegion);
+ void *InsertPos;
+ auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
+
+ if (!R) {
+ R = new (A) RegionTy(arg1, arg2, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ assert(!isAReferenceTypedValueRegion(superRegion));
+ }
+
+ return R;
+}
+
+template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const Arg3Ty arg3,
+ const SuperTy *superRegion) {
+ llvm::FoldingSetNodeID ID;
+ RegionTy::ProfileRegion(ID, arg1, arg2, arg3, superRegion);
+ void *InsertPos;
+ auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
+
+ if (!R) {
+ R = new (A) RegionTy(arg1, arg2, arg3, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ assert(!isAReferenceTypedValueRegion(superRegion));
+ }
+
+ return R;
+}
+
+//===----------------------------------------------------------------------===//
+// Object destruction.
+//===----------------------------------------------------------------------===//
+
+MemRegion::~MemRegion() = default;
+
+// All regions and their data are BumpPtrAllocated. No need to call their
+// destructors.
+MemRegionManager::~MemRegionManager() = default;
+
+//===----------------------------------------------------------------------===//
+// Basic methods.
+//===----------------------------------------------------------------------===//
+
+bool SubRegion::isSubRegionOf(const MemRegion* R) const {
+ const MemRegion* r = this;
+ do {
+ if (r == R)
+ return true;
+ if (const auto *sr = dyn_cast<SubRegion>(r))
+ r = sr->getSuperRegion();
+ else
+ break;
+ } while (r != nullptr);
+ return false;
+}
+
+MemRegionManager &SubRegion::getMemRegionManager() const {
+ const SubRegion* r = this;
+ do {
+ const MemRegion *superRegion = r->getSuperRegion();
+ if (const auto *sr = dyn_cast<SubRegion>(superRegion)) {
+ r = sr;
+ continue;
+ }
+ return superRegion->getMemRegionManager();
+ } while (true);
+}
+
+const StackFrameContext *VarRegion::getStackFrame() const {
+ const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
+ return SSR ? SSR->getStackFrame() : nullptr;
+}
+
+const StackFrameContext *
+CXXLifetimeExtendedObjectRegion::getStackFrame() const {
+ const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
+ return SSR ? SSR->getStackFrame() : nullptr;
+}
+
+const StackFrameContext *CXXTempObjectRegion::getStackFrame() const {
+ assert(isa<StackSpaceRegion>(getRawMemorySpace()) &&
+ "A temporary object can only be allocated on the stack");
+ return cast<StackSpaceRegion>(getRawMemorySpace())->getStackFrame();
+}
+
+ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
+ : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {
+ assert(IVD);
+}
+
+const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { return IVD; }
+
+QualType ObjCIvarRegion::getValueType() const {
+ return getDecl()->getType();
+}
+
+QualType CXXBaseObjectRegion::getValueType() const {
+ return QualType(getDecl()->getTypeForDecl(), 0);
+}
+
+QualType CXXDerivedObjectRegion::getValueType() const {
+ return QualType(getDecl()->getTypeForDecl(), 0);
+}
+
+QualType ParamVarRegion::getValueType() const {
+ assert(getDecl() &&
+ "`ParamVarRegion` support functions without `Decl` not implemented"
+ " yet.");
+ return getDecl()->getType();
+}
+
+const ParmVarDecl *ParamVarRegion::getDecl() const {
+ const Decl *D = getStackFrame()->getDecl();
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ assert(Index < FD->param_size());
+ return FD->parameters()[Index];
+ } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+ assert(Index < BD->param_size());
+ return BD->parameters()[Index];
+ } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ assert(Index < MD->param_size());
+ return MD->parameters()[Index];
+ } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
+ assert(Index < CD->param_size());
+ return CD->parameters()[Index];
+ } else {
+ llvm_unreachable("Unexpected Decl kind!");
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling.
+//===----------------------------------------------------------------------===//
+
+void MemSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(static_cast<unsigned>(getKind()));
+}
+
+void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(static_cast<unsigned>(getKind()));
+ ID.AddPointer(getStackFrame());
+}
+
+void StaticGlobalSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(static_cast<unsigned>(getKind()));
+ ID.AddPointer(getCodeRegion());
+}
+
+void StringRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const StringLiteral *Str,
+ const MemRegion *superRegion) {
+ ID.AddInteger(static_cast<unsigned>(StringRegionKind));
+ ID.AddPointer(Str);
+ ID.AddPointer(superRegion);
+}
+
+void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const ObjCStringLiteral *Str,
+ const MemRegion *superRegion) {
+ ID.AddInteger(static_cast<unsigned>(ObjCStringRegionKind));
+ ID.AddPointer(Str);
+ ID.AddPointer(superRegion);
+}
+
+void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const Expr *Ex, unsigned cnt,
+ const MemRegion *superRegion) {
+ ID.AddInteger(static_cast<unsigned>(AllocaRegionKind));
+ ID.AddPointer(Ex);
+ ID.AddInteger(cnt);
+ ID.AddPointer(superRegion);
+}
+
+void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ ProfileRegion(ID, Ex, Cnt, superRegion);
+}
+
+void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
+}
+
+void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const CompoundLiteralExpr *CL,
+ const MemRegion* superRegion) {
+ ID.AddInteger(static_cast<unsigned>(CompoundLiteralRegionKind));
+ ID.AddPointer(CL);
+ ID.AddPointer(superRegion);
+}
+
+void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const PointerType *PT,
+ const MemRegion *sRegion) {
+ ID.AddInteger(static_cast<unsigned>(CXXThisRegionKind));
+ ID.AddPointer(PT);
+ ID.AddPointer(sRegion);
+}
+
+void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
+}
+
+void FieldRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const ObjCIvarDecl *ivd,
+ const MemRegion* superRegion) {
+ ID.AddInteger(static_cast<unsigned>(ObjCIvarRegionKind));
+ ID.AddPointer(ivd);
+ ID.AddPointer(superRegion);
+}
+
+void ObjCIvarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void NonParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const VarDecl *VD,
+ const MemRegion *superRegion) {
+ ID.AddInteger(static_cast<unsigned>(NonParamVarRegionKind));
+ ID.AddPointer(VD);
+ ID.AddPointer(superRegion);
+}
+
+void NonParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void ParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE,
+ unsigned Idx, const MemRegion *SReg) {
+ ID.AddInteger(static_cast<unsigned>(ParamVarRegionKind));
+ ID.AddPointer(OE);
+ ID.AddInteger(Idx);
+ ID.AddPointer(SReg);
+}
+
+void ParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getOriginExpr(), getIndex(), superRegion);
+}
+
+void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
+ const MemRegion *sreg) {
+ ID.AddInteger(static_cast<unsigned>(MemRegion::SymbolicRegionKind));
+ ID.Add(sym);
+ ID.AddPointer(sreg);
+}
+
+void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ SymbolicRegion::ProfileRegion(ID, sym, getSuperRegion());
+}
+
+void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ QualType ElementType, SVal Idx,
+ const MemRegion* superRegion) {
+ ID.AddInteger(MemRegion::ElementRegionKind);
+ ID.Add(ElementType);
+ ID.AddPointer(superRegion);
+ Idx.Profile(ID);
+}
+
+void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
+}
+
+void FunctionCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const NamedDecl *FD,
+ const MemRegion*) {
+ ID.AddInteger(MemRegion::FunctionCodeRegionKind);
+ ID.AddPointer(FD);
+}
+
+void FunctionCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ FunctionCodeRegion::ProfileRegion(ID, FD, superRegion);
+}
+
+void BlockCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const BlockDecl *BD, CanQualType,
+ const AnalysisDeclContext *AC,
+ const MemRegion*) {
+ ID.AddInteger(MemRegion::BlockCodeRegionKind);
+ ID.AddPointer(BD);
+}
+
+void BlockCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ BlockCodeRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
+}
+
+void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const BlockCodeRegion *BC,
+ const LocationContext *LC,
+ unsigned BlkCount,
+ const MemRegion *sReg) {
+ ID.AddInteger(MemRegion::BlockDataRegionKind);
+ ID.AddPointer(BC);
+ ID.AddPointer(LC);
+ ID.AddInteger(BlkCount);
+ ID.AddPointer(sReg);
+}
+
+void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ BlockDataRegion::ProfileRegion(ID, BC, LC, BlockCount, getSuperRegion());
+}
+
+void CXXTempObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ Expr const *Ex,
+ const MemRegion *sReg) {
+ ID.AddPointer(Ex);
+ ID.AddPointer(sReg);
+}
+
+void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, Ex, getSuperRegion());
+}
+
+void CXXLifetimeExtendedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const Expr *E,
+ const ValueDecl *D,
+ const MemRegion *sReg) {
+ ID.AddPointer(E);
+ ID.AddPointer(D);
+ ID.AddPointer(sReg);
+}
+
+void CXXLifetimeExtendedObjectRegion::Profile(
+ llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, Ex, ExD, getSuperRegion());
+}
+
+void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const CXXRecordDecl *RD,
+ bool IsVirtual,
+ const MemRegion *SReg) {
+ ID.AddPointer(RD);
+ ID.AddBoolean(IsVirtual);
+ ID.AddPointer(SReg);
+}
+
+void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getDecl(), isVirtual(), superRegion);
+}
+
+void CXXDerivedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const CXXRecordDecl *RD,
+ const MemRegion *SReg) {
+ ID.AddPointer(RD);
+ ID.AddPointer(SReg);
+}
+
+void CXXDerivedObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ ProfileRegion(ID, getDecl(), superRegion);
+}
+
+//===----------------------------------------------------------------------===//
+// Region anchors.
+//===----------------------------------------------------------------------===//
+
+void GlobalsSpaceRegion::anchor() {}
+
+void NonStaticGlobalSpaceRegion::anchor() {}
+
+void StackSpaceRegion::anchor() {}
+
+void TypedRegion::anchor() {}
+
+void TypedValueRegion::anchor() {}
+
+void CodeTextRegion::anchor() {}
+
+void SubRegion::anchor() {}
+
+//===----------------------------------------------------------------------===//
+// Region pretty-printing.
+//===----------------------------------------------------------------------===//
+
+LLVM_DUMP_METHOD void MemRegion::dump() const {
+ dumpToStream(llvm::errs());
+}
+
+std::string MemRegion::getString() const {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ dumpToStream(os);
+ return s;
+}
+
+void MemRegion::dumpToStream(raw_ostream &os) const {
+ os << "<Unknown Region>";
+}
+
+void AllocaRegion::dumpToStream(raw_ostream &os) const {
+ os << "alloca{S" << Ex->getID(getContext()) << ',' << Cnt << '}';
+}
+
+void FunctionCodeRegion::dumpToStream(raw_ostream &os) const {
+ os << "code{" << getDecl()->getDeclName().getAsString() << '}';
+}
+
+void BlockCodeRegion::dumpToStream(raw_ostream &os) const {
+ os << "block_code{" << static_cast<const void *>(this) << '}';
+}
+
+void BlockDataRegion::dumpToStream(raw_ostream &os) const {
+ os << "block_data{" << BC;
+ os << "; ";
+ for (auto Var : referenced_vars())
+ os << "(" << Var.getCapturedRegion() << "<-" << Var.getOriginalRegion()
+ << ") ";
+ os << '}';
+}
+
+void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const {
+ // FIXME: More elaborate pretty-printing.
+ os << "{ S" << CL->getID(getContext()) << " }";
+}
+
+void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
+ os << "temp_object{" << getValueType() << ", "
+ << "S" << Ex->getID(getContext()) << '}';
+}
+
+void CXXLifetimeExtendedObjectRegion::dumpToStream(raw_ostream &os) const {
+ os << "lifetime_extended_object{" << getValueType() << ", ";
+ if (const IdentifierInfo *ID = ExD->getIdentifier())
+ os << ID->getName();
+ else
+ os << "D" << ExD->getID();
+ os << ", "
+ << "S" << Ex->getID(getContext()) << '}';
+}
+
+void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
+ os << "Base{" << superRegion << ',' << getDecl()->getName() << '}';
+}
+
+void CXXDerivedObjectRegion::dumpToStream(raw_ostream &os) const {
+ os << "Derived{" << superRegion << ',' << getDecl()->getName() << '}';
+}
+
+void CXXThisRegion::dumpToStream(raw_ostream &os) const {
+ os << "this";
+}
+
+void ElementRegion::dumpToStream(raw_ostream &os) const {
+ os << "Element{" << superRegion << ',' << Index << ',' << getElementType()
+ << '}';
+}
+
+void FieldRegion::dumpToStream(raw_ostream &os) const {
+ os << superRegion << "." << *getDecl();
+}
+
+void ObjCIvarRegion::dumpToStream(raw_ostream &os) const {
+ os << "Ivar{" << superRegion << ',' << *getDecl() << '}';
+}
+
+void StringRegion::dumpToStream(raw_ostream &os) const {
+ assert(Str != nullptr && "Expecting non-null StringLiteral");
+ Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
+}
+
+void ObjCStringRegion::dumpToStream(raw_ostream &os) const {
+ assert(Str != nullptr && "Expecting non-null ObjCStringLiteral");
+ Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
+}
+
+void SymbolicRegion::dumpToStream(raw_ostream &os) const {
+ if (isa<HeapSpaceRegion>(getSuperRegion()))
+ os << "Heap";
+ os << "SymRegion{" << sym << '}';
+}
+
+void NonParamVarRegion::dumpToStream(raw_ostream &os) const {
+ if (const IdentifierInfo *ID = VD->getIdentifier())
+ os << ID->getName();
+ else
+ os << "NonParamVarRegion{D" << VD->getID() << '}';
+}
+
+LLVM_DUMP_METHOD void RegionRawOffset::dump() const {
+ dumpToStream(llvm::errs());
+}
+
+void RegionRawOffset::dumpToStream(raw_ostream &os) const {
+ os << "raw_offset{" << getRegion() << ',' << getOffset().getQuantity() << '}';
+}
+
+void CodeSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "CodeSpaceRegion";
+}
+
+void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "StaticGlobalsMemSpace{" << CR << '}';
+}
+
+void GlobalInternalSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "GlobalInternalSpaceRegion";
+}
+
+void GlobalSystemSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "GlobalSystemSpaceRegion";
+}
+
+void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "GlobalImmutableSpaceRegion";
+}
+
+void HeapSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "HeapSpaceRegion";
+}
+
+void UnknownSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "UnknownSpaceRegion";
+}
+
+void StackArgumentsSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "StackArgumentsSpaceRegion";
+}
+
+void StackLocalsSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "StackLocalsSpaceRegion";
+}
+
+void ParamVarRegion::dumpToStream(raw_ostream &os) const {
+ const ParmVarDecl *PVD = getDecl();
+ assert(PVD &&
+ "`ParamVarRegion` support functions without `Decl` not implemented"
+ " yet.");
+ if (const IdentifierInfo *ID = PVD->getIdentifier()) {
+ os << ID->getName();
+ } else {
+ os << "ParamVarRegion{P" << PVD->getID() << '}';
+ }
+}
+
+bool MemRegion::canPrintPretty() const {
+ return canPrintPrettyAsExpr();
+}
+
+bool MemRegion::canPrintPrettyAsExpr() const {
+ return false;
+}
+
+StringRef MemRegion::getKindStr() const {
+ switch (getKind()) {
+#define REGION(Id, Parent) \
+ case Id##Kind: \
+ return #Id;
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+#undef REGION
+ }
+ llvm_unreachable("Unkown kind!");
+}
+
+void MemRegion::printPretty(raw_ostream &os) const {
+ assert(canPrintPretty() && "This region cannot be printed pretty.");
+ os << "'";
+ printPrettyAsExpr(os);
+ os << "'";
+}
+
+void MemRegion::printPrettyAsExpr(raw_ostream &) const {
+ llvm_unreachable("This region cannot be printed pretty.");
+}
+
+bool NonParamVarRegion::canPrintPrettyAsExpr() const { return true; }
+
+void NonParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+ os << getDecl()->getName();
+}
+
+bool ParamVarRegion::canPrintPrettyAsExpr() const { return true; }
+
+void ParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+ assert(getDecl() &&
+ "`ParamVarRegion` support functions without `Decl` not implemented"
+ " yet.");
+ os << getDecl()->getName();
+}
+
+bool ObjCIvarRegion::canPrintPrettyAsExpr() const {
+ return true;
+}
+
+void ObjCIvarRegion::printPrettyAsExpr(raw_ostream &os) const {
+ os << getDecl()->getName();
+}
+
+bool FieldRegion::canPrintPretty() const {
+ return true;
+}
+
+bool FieldRegion::canPrintPrettyAsExpr() const {
+ return superRegion->canPrintPrettyAsExpr();
+}
+
+void FieldRegion::printPrettyAsExpr(raw_ostream &os) const {
+ assert(canPrintPrettyAsExpr());
+ superRegion->printPrettyAsExpr(os);
+ os << "." << getDecl()->getName();
+}
+
+void FieldRegion::printPretty(raw_ostream &os) const {
+ if (canPrintPrettyAsExpr()) {
+ os << "\'";
+ printPrettyAsExpr(os);
+ os << "'";
+ } else {
+ os << "field " << "\'" << getDecl()->getName() << "'";
+ }
+}
+
+bool CXXBaseObjectRegion::canPrintPrettyAsExpr() const {
+ return superRegion->canPrintPrettyAsExpr();
+}
+
+void CXXBaseObjectRegion::printPrettyAsExpr(raw_ostream &os) const {
+ superRegion->printPrettyAsExpr(os);
+}
+
+bool CXXDerivedObjectRegion::canPrintPrettyAsExpr() const {
+ return superRegion->canPrintPrettyAsExpr();
+}
+
+void CXXDerivedObjectRegion::printPrettyAsExpr(raw_ostream &os) const {
+ superRegion->printPrettyAsExpr(os);
+}
+
+std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
+ std::string VariableName;
+ std::string ArrayIndices;
+ const MemRegion *R = this;
+ SmallString<50> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ // Enclose subject with single quotes if needed.
+ auto QuoteIfNeeded = [UseQuotes](const Twine &Subject) -> std::string {
+ if (UseQuotes)
+ return ("'" + Subject + "'").str();
+ return Subject.str();
+ };
+
+ // Obtain array indices to add them to the variable name.
+ const ElementRegion *ER = nullptr;
+ while ((ER = R->getAs<ElementRegion>())) {
+ // Index is a ConcreteInt.
+ if (auto CI = ER->getIndex().getAs<nonloc::ConcreteInt>()) {
+ llvm::SmallString<2> Idx;
+ CI->getValue()->toString(Idx);
+ ArrayIndices = (llvm::Twine("[") + Idx.str() + "]" + ArrayIndices).str();
+ }
+ // Index is symbolic, but may have a descriptive name.
+ else {
+ auto SI = ER->getIndex().getAs<nonloc::SymbolVal>();
+ if (!SI)
+ return "";
+
+ const MemRegion *OR = SI->getAsSymbol()->getOriginRegion();
+ if (!OR)
+ return "";
+
+ std::string Idx = OR->getDescriptiveName(false);
+ if (Idx.empty())
+ return "";
+
+ ArrayIndices = (llvm::Twine("[") + Idx + "]" + ArrayIndices).str();
+ }
+ R = ER->getSuperRegion();
+ }
+
+ // Get variable name.
+ if (R) {
+ // MemRegion can be pretty printed.
+ if (R->canPrintPrettyAsExpr()) {
+ R->printPrettyAsExpr(os);
+ return QuoteIfNeeded(llvm::Twine(os.str()) + ArrayIndices);
+ }
+
+ // FieldRegion may have ElementRegion as SuperRegion.
+ if (const auto *FR = R->getAs<FieldRegion>()) {
+ std::string Super = FR->getSuperRegion()->getDescriptiveName(false);
+ if (Super.empty())
+ return "";
+ return QuoteIfNeeded(Super + "." + FR->getDecl()->getName());
+ }
+ }
+
+ return VariableName;
+}
+
+SourceRange MemRegion::sourceRange() const {
+ // Check for more specific regions first.
+ if (auto *FR = dyn_cast<FieldRegion>(this)) {
+ return FR->getDecl()->getSourceRange();
+ }
+
+ if (auto *VR = dyn_cast<VarRegion>(this->getBaseRegion())) {
+ return VR->getDecl()->getSourceRange();
+ }
+
+ // Return invalid source range (can be checked by client).
+ return {};
+}
+
+//===----------------------------------------------------------------------===//
+// MemRegionManager methods.
+//===----------------------------------------------------------------------===//
+
+DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
+ SValBuilder &SVB) const {
+ const auto *SR = cast<SubRegion>(MR);
+ SymbolManager &SymMgr = SVB.getSymbolManager();
+
+ switch (SR->getKind()) {
+ case MemRegion::AllocaRegionKind:
+ case MemRegion::SymbolicRegionKind:
+ return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
+ case MemRegion::StringRegionKind:
+ return SVB.makeIntVal(
+ cast<StringRegion>(SR)->getStringLiteral()->getByteLength() + 1,
+ SVB.getArrayIndexType());
+ case MemRegion::CompoundLiteralRegionKind:
+ case MemRegion::CXXBaseObjectRegionKind:
+ case MemRegion::CXXDerivedObjectRegionKind:
+ case MemRegion::CXXTempObjectRegionKind:
+ case MemRegion::CXXLifetimeExtendedObjectRegionKind:
+ case MemRegion::CXXThisRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ case MemRegion::NonParamVarRegionKind:
+ case MemRegion::ParamVarRegionKind:
+ case MemRegion::ElementRegionKind:
+ case MemRegion::ObjCStringRegionKind: {
+ QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
+ if (isa<VariableArrayType>(Ty))
+ return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
+
+ if (Ty->isIncompleteType())
+ return UnknownVal();
+
+ return getElementExtent(Ty, SVB);
+ }
+ case MemRegion::FieldRegionKind: {
+ // Force callers to deal with bitfields explicitly.
+ if (cast<FieldRegion>(SR)->getDecl()->isBitField())
+ return UnknownVal();
+
+ QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
+ const DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB);
+
+ // We currently don't model flexible array members (FAMs), which are:
+ // - int array[]; of IncompleteArrayType
+ // - int array[0]; of ConstantArrayType with size 0
+ // - int array[1]; of ConstantArrayType with size 1
+ // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
+ const auto isFlexibleArrayMemberCandidate =
+ [this](const ArrayType *AT) -> bool {
+ if (!AT)
+ return false;
+
+ auto IsIncompleteArray = [](const ArrayType *AT) {
+ return isa<IncompleteArrayType>(AT);
+ };
+ auto IsArrayOfZero = [](const ArrayType *AT) {
+ const auto *CAT = dyn_cast<ConstantArrayType>(AT);
+ return CAT && CAT->isZeroSize();
+ };
+ auto IsArrayOfOne = [](const ArrayType *AT) {
+ const auto *CAT = dyn_cast<ConstantArrayType>(AT);
+ return CAT && CAT->getSize() == 1;
+ };
+
+ using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+ const FAMKind StrictFlexArraysLevel =
+ Ctx.getLangOpts().getStrictFlexArraysLevel();
+
+ // "Default": Any trailing array member is a FAM.
+ // Since we cannot tell at this point if this array is a trailing member
+ // or not, let's just do the same as for "OneZeroOrIncomplete".
+ if (StrictFlexArraysLevel == FAMKind::Default)
+ return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);
+
+ if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
+ return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);
+
+ if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete)
+ return IsArrayOfZero(AT) || IsIncompleteArray(AT);
+
+ assert(StrictFlexArraysLevel == FAMKind::IncompleteOnly);
+ return IsIncompleteArray(AT);
+ };
+
+ if (isFlexibleArrayMemberCandidate(Ctx.getAsArrayType(Ty)))
+ return UnknownVal();
+
+ return Size;
+ }
+ // FIXME: The following are being used in 'SimpleSValBuilder' and in
+ // 'ArrayBoundChecker::checkLocation' because there is no symbol to
+ // represent the regions more appropriately.
+ case MemRegion::BlockDataRegionKind:
+ case MemRegion::BlockCodeRegionKind:
+ case MemRegion::FunctionCodeRegionKind:
+ return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
+ default:
+ llvm_unreachable("Unhandled region");
+ }
+}
+
+template <typename REG>
+const REG *MemRegionManager::LazyAllocate(REG*& region) {
+ if (!region) {
+ region = new (A) REG(*this);
+ }
+
+ return region;
+}
+
+template <typename REG, typename ARG>
+const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
+ if (!region) {
+ region = new (A) REG(this, a);
+ }
+
+ return region;
+}
+
+const StackLocalsSpaceRegion*
+MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
+ assert(STC);
+ StackLocalsSpaceRegion *&R = StackLocalsSpaceRegions[STC];
+
+ if (R)
+ return R;
+
+ R = new (A) StackLocalsSpaceRegion(*this, STC);
+ return R;
+}
+
+const StackArgumentsSpaceRegion *
+MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
+ assert(STC);
+ StackArgumentsSpaceRegion *&R = StackArgumentsSpaceRegions[STC];
+
+ if (R)
+ return R;
+
+ R = new (A) StackArgumentsSpaceRegion(*this, STC);
+ return R;
+}
+
+const GlobalsSpaceRegion
+*MemRegionManager::getGlobalsRegion(MemRegion::Kind K,
+ const CodeTextRegion *CR) {
+ if (!CR) {
+ if (K == MemRegion::GlobalSystemSpaceRegionKind)
+ return LazyAllocate(SystemGlobals);
+ if (K == MemRegion::GlobalImmutableSpaceRegionKind)
+ return LazyAllocate(ImmutableGlobals);
+ assert(K == MemRegion::GlobalInternalSpaceRegionKind);
+ return LazyAllocate(InternalGlobals);
+ }
+
+ assert(K == MemRegion::StaticGlobalSpaceRegionKind);
+ StaticGlobalSpaceRegion *&R = StaticsGlobalSpaceRegions[CR];
+ if (R)
+ return R;
+
+ R = new (A) StaticGlobalSpaceRegion(*this, CR);
+ return R;
+}
+
+const HeapSpaceRegion *MemRegionManager::getHeapRegion() {
+ return LazyAllocate(heap);
+}
+
+const UnknownSpaceRegion *MemRegionManager::getUnknownRegion() {
+ return LazyAllocate(unknown);
+}
+
+const CodeSpaceRegion *MemRegionManager::getCodeRegion() {
+ return LazyAllocate(code);
+}
+
+//===----------------------------------------------------------------------===//
+// Constructing regions.
+//===----------------------------------------------------------------------===//
+
+const StringRegion *MemRegionManager::getStringRegion(const StringLiteral *Str){
+ return getSubRegion<StringRegion>(
+ Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
+}
+
+const ObjCStringRegion *
+MemRegionManager::getObjCStringRegion(const ObjCStringLiteral *Str){
+ return getSubRegion<ObjCStringRegion>(
+ Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
+}
+
+/// Look through a chain of LocationContexts to either find the
+/// StackFrameContext that matches a DeclContext, or find a VarRegion
+/// for a variable captured by a block.
+static llvm::PointerUnion<const StackFrameContext *, const VarRegion *>
+getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
+ const DeclContext *DC,
+ const VarDecl *VD) {
+ while (LC) {
+ if (const auto *SFC = dyn_cast<StackFrameContext>(LC)) {
+ if (cast<DeclContext>(SFC->getDecl()) == DC)
+ return SFC;
+ }
+ if (const auto *BC = dyn_cast<BlockInvocationContext>(LC)) {
+ const auto *BR = static_cast<const BlockDataRegion *>(BC->getData());
+ // FIXME: This can be made more efficient.
+ for (auto Var : BR->referenced_vars()) {
+ const TypedValueRegion *OrigR = Var.getOriginalRegion();
+ if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {
+ if (VR->getDecl() == VD)
+ return cast<VarRegion>(Var.getCapturedRegion());
+ }
+ }
+ }
+
+ LC = LC->getParent();
+ }
+ return (const StackFrameContext *)nullptr;
+}
+
+const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
+ const LocationContext *LC) {
+ const auto *PVD = dyn_cast<ParmVarDecl>(D);
+ if (PVD) {
+ unsigned Index = PVD->getFunctionScopeIndex();
+ const StackFrameContext *SFC = LC->getStackFrame();
+ const Stmt *CallSite = SFC->getCallSite();
+ if (CallSite) {
+ const Decl *D = SFC->getDecl();
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (Index < FD->param_size() && FD->parameters()[Index] == PVD)
+ return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+ getStackArgumentsRegion(SFC));
+ } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+ if (Index < BD->param_size() && BD->parameters()[Index] == PVD)
+ return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+ getStackArgumentsRegion(SFC));
+ } else {
+ return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+ getStackArgumentsRegion(SFC));
+ }
+ }
+ }
+
+ D = D->getCanonicalDecl();
+ const MemRegion *sReg = nullptr;
+
+ if (D->hasGlobalStorage() && !D->isStaticLocal()) {
+ QualType Ty = D->getType();
+ assert(!Ty.isNull());
+ if (Ty.isConstQualified()) {
+ sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
+ } else if (Ctx.getSourceManager().isInSystemHeader(D->getLocation())) {
+ sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
+ } else {
+ sReg = getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind);
+ }
+
+ // Finally handle static locals.
+ } else {
+ // FIXME: Once we implement scope handling, we will need to properly lookup
+ // 'D' to the proper LocationContext.
+ const DeclContext *DC = D->getDeclContext();
+ llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V =
+ getStackOrCaptureRegionForDeclContext(LC, DC, D);
+
+ if (const auto *VR = dyn_cast_if_present<const VarRegion *>(V))
+ return VR;
+
+ const auto *STC = cast<const StackFrameContext *>(V);
+
+ if (!STC) {
+ // FIXME: Assign a more sensible memory space to static locals
+ // we see from within blocks that we analyze as top-level declarations.
+ sReg = getUnknownRegion();
+ } else {
+ if (D->hasLocalStorage()) {
+ sReg =
+ isa<ParmVarDecl, ImplicitParamDecl>(D)
+ ? static_cast<const MemRegion *>(getStackArgumentsRegion(STC))
+ : static_cast<const MemRegion *>(getStackLocalsRegion(STC));
+ }
+ else {
+ assert(D->isStaticLocal());
+ const Decl *STCD = STC->getDecl();
+ if (isa<FunctionDecl, ObjCMethodDecl>(STCD))
+ sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
+ getFunctionCodeRegion(cast<NamedDecl>(STCD)));
+ else if (const auto *BD = dyn_cast<BlockDecl>(STCD)) {
+ // FIXME: The fallback type here is totally bogus -- though it should
+ // never be queried, it will prevent uniquing with the real
+ // BlockCodeRegion. Ideally we'd fix the AST so that we always had a
+ // signature.
+ QualType T;
+ if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
+ T = TSI->getType();
+ if (T.isNull())
+ T = getContext().VoidTy;
+ if (!T->getAs<FunctionType>()) {
+ FunctionProtoType::ExtProtoInfo Ext;
+ T = getContext().getFunctionType(T, {}, Ext);
+ }
+ T = getContext().getBlockPointerType(T);
+
+ const BlockCodeRegion *BTR =
+ getBlockCodeRegion(BD, Ctx.getCanonicalType(T),
+ STC->getAnalysisDeclContext());
+ sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
+ BTR);
+ }
+ else {
+ sReg = getGlobalsRegion();
+ }
+ }
+ }
+ }
+
+ return getNonParamVarRegion(D, sReg);
+}
+
+const NonParamVarRegion *
+MemRegionManager::getNonParamVarRegion(const VarDecl *D,
+ const MemRegion *superR) {
+ // Prefer the definition over the canonical decl as the canonical form.
+ D = D->getCanonicalDecl();
+ if (const VarDecl *Def = D->getDefinition())
+ D = Def;
+ return getSubRegion<NonParamVarRegion>(D, superR);
+}
+
+const ParamVarRegion *
+MemRegionManager::getParamVarRegion(const Expr *OriginExpr, unsigned Index,
+ const LocationContext *LC) {
+ const StackFrameContext *SFC = LC->getStackFrame();
+ assert(SFC);
+ return getSubRegion<ParamVarRegion>(OriginExpr, Index,
+ getStackArgumentsRegion(SFC));
+}
+
+const BlockDataRegion *
+MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
+ const LocationContext *LC,
+ unsigned blockCount) {
+ const MemSpaceRegion *sReg = nullptr;
+ const BlockDecl *BD = BC->getDecl();
+ if (!BD->hasCaptures()) {
+ // This handles 'static' blocks.
+ sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
+ }
+ else {
+ bool IsArcManagedBlock = Ctx.getLangOpts().ObjCAutoRefCount;
+
+ // ARC managed blocks can be initialized on stack or directly in heap
+ // depending on the implementations. So we initialize them with
+ // UnknownRegion.
+ if (!IsArcManagedBlock && LC) {
+ // FIXME: Once we implement scope handling, we want the parent region
+ // to be the scope.
+ const StackFrameContext *STC = LC->getStackFrame();
+ assert(STC);
+ sReg = getStackLocalsRegion(STC);
+ } else {
+ // We allow 'LC' to be NULL for cases where want BlockDataRegions
+ // without context-sensitivity.
+ sReg = getUnknownRegion();
+ }
+ }
+
+ return getSubRegion<BlockDataRegion>(BC, LC, blockCount, sReg);
+}
+
+const CompoundLiteralRegion*
+MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
+ const LocationContext *LC) {
+ const MemSpaceRegion *sReg = nullptr;
+
+ if (CL->isFileScope())
+ sReg = getGlobalsRegion();
+ else {
+ const StackFrameContext *STC = LC->getStackFrame();
+ assert(STC);
+ sReg = getStackLocalsRegion(STC);
+ }
+
+ return getSubRegion<CompoundLiteralRegion>(CL, sReg);
+}
+
+const ElementRegion *
+MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
+ const SubRegion *superRegion,
+ const ASTContext &Ctx) {
+ QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType();
+
+ llvm::FoldingSetNodeID ID;
+ ElementRegion::ProfileRegion(ID, T, Idx, superRegion);
+
+ void *InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ auto *R = cast_or_null<ElementRegion>(data);
+
+ if (!R) {
+ R = new (A) ElementRegion(T, Idx, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+const FunctionCodeRegion *
+MemRegionManager::getFunctionCodeRegion(const NamedDecl *FD) {
+ // To think: should we canonicalize the declaration here?
+ return getSubRegion<FunctionCodeRegion>(FD, getCodeRegion());
+}
+
+const BlockCodeRegion *
+MemRegionManager::getBlockCodeRegion(const BlockDecl *BD, CanQualType locTy,
+ AnalysisDeclContext *AC) {
+ return getSubRegion<BlockCodeRegion>(BD, locTy, AC, getCodeRegion());
+}
+
+const SymbolicRegion *
+MemRegionManager::getSymbolicRegion(SymbolRef sym,
+ const MemSpaceRegion *MemSpace) {
+ if (MemSpace == nullptr)
+ MemSpace = getUnknownRegion();
+ return getSubRegion<SymbolicRegion>(sym, MemSpace);
+}
+
+const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) {
+ return getSubRegion<SymbolicRegion>(Sym, getHeapRegion());
+}
+
+const FieldRegion*
+MemRegionManager::getFieldRegion(const FieldDecl *d,
+ const SubRegion* superRegion){
+ return getSubRegion<FieldRegion>(d, superRegion);
+}
+
+const ObjCIvarRegion*
+MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl *d,
+ const SubRegion* superRegion) {
+ return getSubRegion<ObjCIvarRegion>(d, superRegion);
+}
+
+const CXXTempObjectRegion*
+MemRegionManager::getCXXTempObjectRegion(Expr const *E,
+ LocationContext const *LC) {
+ const StackFrameContext *SFC = LC->getStackFrame();
+ assert(SFC);
+ return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));
+}
+
+const CXXLifetimeExtendedObjectRegion *
+MemRegionManager::getCXXLifetimeExtendedObjectRegion(
+ const Expr *Ex, const ValueDecl *VD, const LocationContext *LC) {
+ const StackFrameContext *SFC = LC->getStackFrame();
+ assert(SFC);
+ return getSubRegion<CXXLifetimeExtendedObjectRegion>(
+ Ex, VD, getStackLocalsRegion(SFC));
+}
+
+const CXXLifetimeExtendedObjectRegion *
+MemRegionManager::getCXXStaticLifetimeExtendedObjectRegion(
+ const Expr *Ex, const ValueDecl *VD) {
+ return getSubRegion<CXXLifetimeExtendedObjectRegion>(
+ Ex, VD,
+ getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr));
+}
+
+/// Checks whether \p BaseClass is a valid virtual or direct non-virtual base
+/// class of the type of \p Super.
+static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
+ const TypedValueRegion *Super,
+ bool IsVirtual) {
+ BaseClass = BaseClass->getCanonicalDecl();
+
+ const CXXRecordDecl *Class = Super->getValueType()->getAsCXXRecordDecl();
+ if (!Class)
+ return true;
+
+ if (IsVirtual)
+ return Class->isVirtuallyDerivedFrom(BaseClass);
+
+ for (const auto &I : Class->bases()) {
+ if (I.getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
+ return true;
+ }
+
+ return false;
+}
+
+const CXXBaseObjectRegion *
+MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
+ const SubRegion *Super,
+ bool IsVirtual) {
+ if (isa<TypedValueRegion>(Super)) {
+ assert(isValidBaseClass(RD, cast<TypedValueRegion>(Super), IsVirtual));
+ (void)&isValidBaseClass;
+
+ if (IsVirtual) {
+ // Virtual base regions should not be layered, since the layout rules
+ // are different.
+ while (const auto *Base = dyn_cast<CXXBaseObjectRegion>(Super))
+ Super = cast<SubRegion>(Base->getSuperRegion());
+ assert(Super && !isa<MemSpaceRegion>(Super));
+ }
+ }
+
+ return getSubRegion<CXXBaseObjectRegion>(RD, IsVirtual, Super);
+}
+
+const CXXDerivedObjectRegion *
+MemRegionManager::getCXXDerivedObjectRegion(const CXXRecordDecl *RD,
+ const SubRegion *Super) {
+ return getSubRegion<CXXDerivedObjectRegion>(RD, Super);
+}
+
+const CXXThisRegion*
+MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
+ const LocationContext *LC) {
+ const auto *PT = thisPointerTy->getAs<PointerType>();
+ assert(PT);
+ // Inside the body of the operator() of a lambda a this expr might refer to an
+ // object in one of the parent location contexts.
+ const auto *D = dyn_cast<CXXMethodDecl>(LC->getDecl());
+ // FIXME: when operator() of lambda is analyzed as a top level function and
+ // 'this' refers to a this to the enclosing scope, there is no right region to
+ // return.
+ while (!LC->inTopFrame() && (!D || D->isStatic() ||
+ PT != D->getThisType()->getAs<PointerType>())) {
+ LC = LC->getParent();
+ D = dyn_cast<CXXMethodDecl>(LC->getDecl());
+ }
+ const StackFrameContext *STC = LC->getStackFrame();
+ assert(STC);
+ return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
+}
+
+const AllocaRegion*
+MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt,
+ const LocationContext *LC) {
+ const StackFrameContext *STC = LC->getStackFrame();
+ assert(STC);
+ return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
+}
+
+const MemSpaceRegion *MemRegion::getRawMemorySpace() const {
+ const MemRegion *R = this;
+ const auto *SR = dyn_cast<SubRegion>(this);
+
+ while (SR) {
+ R = SR->getSuperRegion();
+ SR = dyn_cast<SubRegion>(R);
+ }
+
+ return cast<MemSpaceRegion>(R);
+}
+
+const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
+ const MemRegion *MR = getBaseRegion();
+
+ const MemSpaceRegion *MS = MR->getRawMemorySpace();
+ if (!isa<UnknownSpaceRegion>(MS))
+ return MS;
+
+ const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
+ return Result ? *Result : MS;
+}
+
+ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const {
+ const MemRegion *MR = getBaseRegion();
+
+ // For now, this should only be called to update the trait for memory regions
+ // that have an unknown memory spaces since we assume everywhere else that the
+ // memory space trait is set only for unknown memory spaces (setting this info
+ // otherwise would go unused).
+ assert(isa<UnknownSpaceRegion>(MR->getRawMemorySpace()));
+
+ // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
+ // an already UnknownSpaceRegion
+ assert(!isa<UnknownSpaceRegion>(MS));
+
+ ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
+ return NewState;
+}
+
+bool MemRegion::hasRawStackStorage() const {
+ return isa<StackSpaceRegion>(getRawMemorySpace());
+}
+
+bool MemRegion::hasStackStorage(ProgramStateRef State) const {
+ return isMemorySpace<StackSpaceRegion>(State);
+}
+
+bool MemRegion::hasRawStackNonParametersStorage() const {
+ return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
+}
+
+bool MemRegion::hasStackNonParametersStorage(ProgramStateRef State) const {
+ return isMemorySpace<StackLocalsSpaceRegion>(State);
+}
+
+bool MemRegion::hasRawStackParametersStorage() const {
+ return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
+}
+
+bool MemRegion::hasStackParametersStorage(ProgramStateRef State) const {
+ return isMemorySpace<StackArgumentsSpaceRegion>(State);
+}
+
+// Strips away all elements and fields.
+// Returns the base region of them.
+const MemRegion *MemRegion::getBaseRegion() const {
+ const MemRegion *R = this;
+ while (true) {
+ switch (R->getKind()) {
+ case MemRegion::ElementRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ case MemRegion::CXXBaseObjectRegionKind:
+ case MemRegion::CXXDerivedObjectRegionKind:
+ R = cast<SubRegion>(R)->getSuperRegion();
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ return R;
+}
+
+// Returns the region of the root class of a C++ class hierarchy.
+const MemRegion *MemRegion::getMostDerivedObjectRegion() const {
+ const MemRegion *R = this;
+ while (const auto *BR = dyn_cast<CXXBaseObjectRegion>(R))
+ R = BR->getSuperRegion();
+ return R;
+}
+
+bool MemRegion::isSubRegionOf(const MemRegion *) const {
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// View handling.
+//===----------------------------------------------------------------------===//
+
+const MemRegion *MemRegion::StripCasts(bool StripBaseAndDerivedCasts) const {
+ const MemRegion *R = this;
+ while (true) {
+ switch (R->getKind()) {
+ case ElementRegionKind: {
+ const auto *ER = cast<ElementRegion>(R);
+ if (!ER->getIndex().isZeroConstant())
+ return R;
+ R = ER->getSuperRegion();
+ break;
+ }
+ case CXXBaseObjectRegionKind:
+ case CXXDerivedObjectRegionKind:
+ if (!StripBaseAndDerivedCasts)
+ return R;
+ R = cast<TypedValueRegion>(R)->getSuperRegion();
+ break;
+ default:
+ return R;
+ }
+ }
+}
+
+const SymbolicRegion *MemRegion::getSymbolicBase() const {
+ const auto *SubR = dyn_cast<SubRegion>(this);
+
+ while (SubR) {
+ if (const auto *SymR = dyn_cast<SymbolicRegion>(SubR))
+ return SymR;
+ SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
+ }
+ return nullptr;
+}
+
+RegionRawOffset ElementRegion::getAsArrayOffset() const {
+ int64_t offset = 0;
+ const ElementRegion *ER = this;
+ const MemRegion *superR = nullptr;
+ ASTContext &C = getContext();
+
+ // FIXME: Handle multi-dimensional arrays.
+
+ while (ER) {
+ superR = ER->getSuperRegion();
+
+ // FIXME: generalize to symbolic offsets.
+ SVal index = ER->getIndex();
+ if (auto CI = index.getAs<nonloc::ConcreteInt>()) {
+ // Update the offset.
+ if (int64_t i = CI->getValue()->getSExtValue(); i != 0) {
+ QualType elemType = ER->getElementType();
+
+ // If we are pointing to an incomplete type, go no further.
+ if (elemType->isIncompleteType()) {
+ superR = ER;
+ break;
+ }
+
+ int64_t size = C.getTypeSizeInChars(elemType).getQuantity();
+ if (auto NewOffset = llvm::checkedMulAdd(i, size, offset)) {
+ offset = *NewOffset;
+ } else {
+ LLVM_DEBUG(llvm::dbgs() << "MemRegion::getAsArrayOffset: "
+ << "offset overflowing, returning unknown\n");
+
+ return nullptr;
+ }
+ }
+
+ // Go to the next ElementRegion (if any).
+ ER = dyn_cast<ElementRegion>(superR);
+ continue;
+ }
+
+ return nullptr;
+ }
+
+ assert(superR && "super region cannot be NULL");
+ return RegionRawOffset(superR, CharUnits::fromQuantity(offset));
+}
+
+/// Returns true if \p Base is an immediate base class of \p Child
+static bool isImmediateBase(const CXXRecordDecl *Child,
+ const CXXRecordDecl *Base) {
+ assert(Child && "Child must not be null");
+ // Note that we do NOT canonicalize the base class here, because
+ // ASTRecordLayout doesn't either. If that leads us down the wrong path,
+ // so be it; at least we won't crash.
+ for (const auto &I : Child->bases()) {
+ if (I.getType()->getAsCXXRecordDecl() == Base)
+ return true;
+ }
+
+ return false;
+}
+
+static RegionOffset calculateOffset(const MemRegion *R) {
+ const MemRegion *SymbolicOffsetBase = nullptr;
+ int64_t Offset = 0;
+
+ while (true) {
+ switch (R->getKind()) {
+ case MemRegion::CodeSpaceRegionKind:
+ case MemRegion::StackLocalsSpaceRegionKind:
+ case MemRegion::StackArgumentsSpaceRegionKind:
+ case MemRegion::HeapSpaceRegionKind:
+ case MemRegion::UnknownSpaceRegionKind:
+ case MemRegion::StaticGlobalSpaceRegionKind:
+ case MemRegion::GlobalInternalSpaceRegionKind:
+ case MemRegion::GlobalSystemSpaceRegionKind:
+ case MemRegion::GlobalImmutableSpaceRegionKind:
+ // Stores can bind directly to a region space to set a default value.
+ assert(Offset == 0 && !SymbolicOffsetBase);
+ goto Finish;
+
+ case MemRegion::FunctionCodeRegionKind:
+ case MemRegion::BlockCodeRegionKind:
+ case MemRegion::BlockDataRegionKind:
+ // These will never have bindings, but may end up having values requested
+ // if the user does some strange casting.
+ if (Offset != 0)
+ SymbolicOffsetBase = R;
+ goto Finish;
+
+ case MemRegion::SymbolicRegionKind:
+ case MemRegion::AllocaRegionKind:
+ case MemRegion::CompoundLiteralRegionKind:
+ case MemRegion::CXXThisRegionKind:
+ case MemRegion::StringRegionKind:
+ case MemRegion::ObjCStringRegionKind:
+ case MemRegion::NonParamVarRegionKind:
+ case MemRegion::ParamVarRegionKind:
+ case MemRegion::CXXTempObjectRegionKind:
+ case MemRegion::CXXLifetimeExtendedObjectRegionKind:
+ // Usual base regions.
+ goto Finish;
+
+ case MemRegion::ObjCIvarRegionKind:
+ // This is a little strange, but it's a compromise between
+ // ObjCIvarRegions having unknown compile-time offsets (when using the
+ // non-fragile runtime) and yet still being distinct, non-overlapping
+ // regions. Thus we treat them as "like" base regions for the purposes
+ // of computing offsets.
+ goto Finish;
+
+ case MemRegion::CXXBaseObjectRegionKind: {
+ const auto *BOR = cast<CXXBaseObjectRegion>(R);
+ R = BOR->getSuperRegion();
+
+ QualType Ty;
+ bool RootIsSymbolic = false;
+ if (const auto *TVR = dyn_cast<TypedValueRegion>(R)) {
+ Ty = TVR->getDesugaredValueType(R->getContext());
+ } else if (const auto *SR = dyn_cast<SymbolicRegion>(R)) {
+ // If our base region is symbolic, we don't know what type it really is.
+ // Pretend the type of the symbol is the true dynamic type.
+ // (This will at least be self-consistent for the life of the symbol.)
+ Ty = SR->getPointeeStaticType();
+ RootIsSymbolic = true;
+ }
+
+ const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
+ if (!Child) {
+ // We cannot compute the offset of the base class.
+ SymbolicOffsetBase = R;
+ } else {
+ if (RootIsSymbolic) {
+ // Base layers on symbolic regions may not be type-correct.
+ // Double-check the inheritance here, and revert to a symbolic offset
+ // if it's invalid (e.g. due to a reinterpret_cast).
+ if (BOR->isVirtual()) {
+ if (!Child->isVirtuallyDerivedFrom(BOR->getDecl()))
+ SymbolicOffsetBase = R;
+ } else {
+ if (!isImmediateBase(Child, BOR->getDecl()))
+ SymbolicOffsetBase = R;
+ }
+ }
+ }
+
+ // Don't bother calculating precise offsets if we already have a
+ // symbolic offset somewhere in the chain.
+ if (SymbolicOffsetBase)
+ continue;
+
+ CharUnits BaseOffset;
+ const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(Child);
+ if (BOR->isVirtual())
+ BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
+ else
+ BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
+
+ // The base offset is in chars, not in bits.
+ Offset += BaseOffset.getQuantity() * R->getContext().getCharWidth();
+ break;
+ }
+
+ case MemRegion::CXXDerivedObjectRegionKind: {
+ // TODO: Store the base type in the CXXDerivedObjectRegion and use it.
+ goto Finish;
+ }
+
+ case MemRegion::ElementRegionKind: {
+ const auto *ER = cast<ElementRegion>(R);
+ R = ER->getSuperRegion();
+
+ QualType EleTy = ER->getValueType();
+ if (EleTy->isIncompleteType()) {
+ // We cannot compute the offset of the base class.
+ SymbolicOffsetBase = R;
+ continue;
+ }
+
+ SVal Index = ER->getIndex();
+ if (std::optional<nonloc::ConcreteInt> CI =
+ Index.getAs<nonloc::ConcreteInt>()) {
+ // Don't bother calculating precise offsets if we already have a
+ // symbolic offset somewhere in the chain.
+ if (SymbolicOffsetBase)
+ continue;
+
+ int64_t i = CI->getValue()->getSExtValue();
+ // This type size is in bits.
+ Offset += i * R->getContext().getTypeSize(EleTy);
+ } else {
+ // We cannot compute offset for non-concrete index.
+ SymbolicOffsetBase = R;
+ }
+ break;
+ }
+ case MemRegion::FieldRegionKind: {
+ const auto *FR = cast<FieldRegion>(R);
+ R = FR->getSuperRegion();
+ assert(R);
+
+ const RecordDecl *RD = FR->getDecl()->getParent();
+ if (RD->isUnion() || !RD->isCompleteDefinition()) {
+ // We cannot compute offset for incomplete type.
+ // For unions, we could treat everything as offset 0, but we'd rather
+ // treat each field as a symbolic offset so they aren't stored on top
+ // of each other, since we depend on things in typed regions actually
+ // matching their types.
+ SymbolicOffsetBase = R;
+ }
+
+ // Don't bother calculating precise offsets if we already have a
+ // symbolic offset somewhere in the chain.
+ if (SymbolicOffsetBase)
+ continue;
+
+ // Get the field number.
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end(); FI != FE; ++FI, ++idx) {
+ if (FR->getDecl() == *FI)
+ break;
+ }
+ const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(RD);
+ // This is offset in bits.
+ Offset += Layout.getFieldOffset(idx);
+ break;
+ }
+ }
+ }
+
+ Finish:
+ if (SymbolicOffsetBase)
+ return RegionOffset(SymbolicOffsetBase, RegionOffset::Symbolic);
+ return RegionOffset(R, Offset);
+}
+
+RegionOffset MemRegion::getAsOffset() const {
+ if (!cachedOffset)
+ cachedOffset = calculateOffset(this);
+ return *cachedOffset;
+}
+
+//===----------------------------------------------------------------------===//
+// BlockDataRegion
+//===----------------------------------------------------------------------===//
+
+std::pair<const VarRegion *, const VarRegion *>
+BlockDataRegion::getCaptureRegions(const VarDecl *VD) {
+ MemRegionManager &MemMgr = getMemRegionManager();
+ const VarRegion *VR = nullptr;
+ const VarRegion *OriginalVR = nullptr;
+
+ if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) {
+ VR = MemMgr.getNonParamVarRegion(VD, this);
+ OriginalVR = MemMgr.getVarRegion(VD, LC);
+ }
+ else {
+ if (LC) {
+ VR = MemMgr.getVarRegion(VD, LC);
+ OriginalVR = VR;
+ }
+ else {
+ VR = MemMgr.getNonParamVarRegion(VD, MemMgr.getUnknownRegion());
+ OriginalVR = MemMgr.getVarRegion(VD, LC);
+ }
+ }
+ return std::make_pair(VR, OriginalVR);
+}
+
+void BlockDataRegion::LazyInitializeReferencedVars() {
+ if (ReferencedVars)
+ return;
+
+ AnalysisDeclContext *AC = getCodeRegion()->getAnalysisDeclContext();
+ const auto &ReferencedBlockVars = AC->getReferencedBlockVars(BC->getDecl());
+ auto NumBlockVars =
+ std::distance(ReferencedBlockVars.begin(), ReferencedBlockVars.end());
+
+ if (NumBlockVars == 0) {
+ ReferencedVars = (void*) 0x1;
+ return;
+ }
+
+ MemRegionManager &MemMgr = getMemRegionManager();
+ llvm::BumpPtrAllocator &A = MemMgr.getAllocator();
+ BumpVectorContext BC(A);
+
+ using VarVec = BumpVector<const MemRegion *>;
+
+ auto *BV = new (A) VarVec(BC, NumBlockVars);
+ auto *BVOriginal = new (A) VarVec(BC, NumBlockVars);
+
+ for (const auto *VD : ReferencedBlockVars) {
+ const VarRegion *VR = nullptr;
+ const VarRegion *OriginalVR = nullptr;
+ std::tie(VR, OriginalVR) = getCaptureRegions(VD);
+ assert(VR);
+ assert(OriginalVR);
+ BV->push_back(VR, BC);
+ BVOriginal->push_back(OriginalVR, BC);
+ }
+
+ ReferencedVars = BV;
+ OriginalVars = BVOriginal;
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_begin() const {
+ const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+ auto *Vec = static_cast<BumpVector<const MemRegion *> *>(ReferencedVars);
+
+ if (Vec == (void*) 0x1)
+ return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
+
+ auto *VecOriginal =
+ static_cast<BumpVector<const MemRegion *> *>(OriginalVars);
+
+ return BlockDataRegion::referenced_vars_iterator(Vec->begin(),
+ VecOriginal->begin());
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_end() const {
+ const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+ auto *Vec = static_cast<BumpVector<const MemRegion *> *>(ReferencedVars);
+
+ if (Vec == (void*) 0x1)
+ return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
+
+ auto *VecOriginal =
+ static_cast<BumpVector<const MemRegion *> *>(OriginalVars);
+
+ return BlockDataRegion::referenced_vars_iterator(Vec->end(),
+ VecOriginal->end());
+}
+
+llvm::iterator_range<BlockDataRegion::referenced_vars_iterator>
+BlockDataRegion::referenced_vars() const {
+ return llvm::make_range(referenced_vars_begin(), referenced_vars_end());
+}
+
+const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
+ for (const auto &I : referenced_vars()) {
+ if (I.getCapturedRegion() == R)
+ return I.getOriginalRegion();
+ }
+ return nullptr;
+}
+
+//===----------------------------------------------------------------------===//
+// RegionAndSymbolInvalidationTraits
+//===----------------------------------------------------------------------===//
+
+void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym,
+ InvalidationKinds IK) {
+ SymTraitsMap[Sym] |= IK;
+}
+
+void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
+ InvalidationKinds IK) {
+ assert(MR);
+ if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
+ setTrait(SR->getSymbol(), IK);
+ else
+ MRTraitsMap[MR] |= IK;
+}
+
+bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym,
+ InvalidationKinds IK) const {
+ const_symbol_iterator I = SymTraitsMap.find(Sym);
+ if (I != SymTraitsMap.end())
+ return I->second & IK;
+
+ return false;
+}
+
+bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,
+ InvalidationKinds IK) const {
+ if (!MR)
+ return false;
+
+ if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
+ return hasTrait(SR->getSymbol(), IK);
+
+ const_region_iterator I = MRTraitsMap.find(MR);
+ if (I != MRTraitsMap.end())
+ return I->second & IK;
+
+ return false;
+}
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
deleted file mode 100644
index 8221b79b0706c6..00000000000000
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===-- MemSpaces.cpp ---------------------------------------------*- 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 getters and setters for the memory space trait which
-// associates memory regions with memory spaces in the program state. It also
-// defines the MemSpacesMap which maps memory regions to memory spaces.
-//
-// These functions keep the following invariants over the MemSpacesMap:
-// 1. (Temporary as an intermediate step) Memory space traits are only
-// mapped for memory regions that have an unknown memory space
-// 2. Only base memory regions are mapped in the trait
-// 3. Memory regions which have no mapping in the trait are assumed to be
-// unknown; no memory region is allowed to be mapped to an unknown memory
-// space in the trait;
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include <cassert>
-
-REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
- const clang::ento::MemSpaceRegion *)
-
-namespace clang {
-namespace ento {
-namespace memspace {} // namespace memspace
-} // namespace ento
-} // namespace clang
>From af52435ad56957f99c6afb7bd2a7c10798b7156e Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 13:13:33 -0600
Subject: [PATCH 21/21] formatting
---
clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 4b621e5cb4f975..0741ce2308aa3e 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1369,12 +1369,13 @@ const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
const MemSpaceRegion *MS = MR->getRawMemorySpace();
if (!isa<UnknownSpaceRegion>(MS))
return MS;
-
+
const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
return Result ? *Result : MS;
}
-ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const {
+ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State,
+ const MemSpaceRegion *MS) const {
const MemRegion *MR = getBaseRegion();
// For now, this should only be called to update the trait for memory regions
@@ -1395,8 +1396,8 @@ bool MemRegion::hasRawStackStorage() const {
return isa<StackSpaceRegion>(getRawMemorySpace());
}
-bool MemRegion::hasStackStorage(ProgramStateRef State) const {
- return isMemorySpace<StackSpaceRegion>(State);
+bool MemRegion::hasStackStorage(ProgramStateRef State) const {
+ return isMemorySpace<StackSpaceRegion>(State);
}
bool MemRegion::hasRawStackNonParametersStorage() const {
More information about the cfe-commits
mailing list