Balazs Benics 6171e4b34b
Revert "[Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured" (#137304)
Reverts llvm/llvm-project#128251

ASAN bots reported some errors:
https://lab.llvm.org/buildbot/#/builders/55/builds/10398
Reverting for investigation.

```
Failed Tests (6):
  Clang :: Analysis/loop-widening-ignore-static-methods.cpp
  Clang :: Analysis/loop-widening-notes.cpp
  Clang :: Analysis/loop-widening-preserve-reference-type.cpp
  Clang :: Analysis/loop-widening.c
  Clang :: Analysis/loop-widening.cpp
  Clang :: Analysis/this-pointer.cpp
Testing Time: 411.55s
Total Discovered Tests: 118563
  Skipped          :     33 (0.03%)
  Unsupported      :   2015 (1.70%)
  Passed           : 116291 (98.08%)
  Expectedly Failed:    218 (0.18%)
  Failed           :      6 (0.01%)
FAILED: CMakeFiles/check-all /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/CMakeFiles/check-all 
cd /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan && /usr/bin/python3 /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/./bin/llvm-lit -sv --param USE_Z3_SOLVER=0 /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/utils/mlgo-utils /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/tools/lld/test /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/tools/mlir/test /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/tools/clang/test /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/utils/lit /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/test
ninja: build stopped: subcommand failed.
```

```
/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/bin/clang -cc1 -internal-isystem /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify -analyzer-config eagerly-assume=false /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/test/Analysis/loop-widening.c # RUN: at line 1
+ /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/bin/clang -cc1 -internal-isystem /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify -analyzer-config eagerly-assume=false /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/test/Analysis/loop-widening.c
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/bin/clang -cc1 -internal-isystem /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify -analyzer-config eagerly-assume=false /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/test/Analysis/loop-widening.c
1.	<eof> parser at end of file
2.	While analyzing stack: 
	#0 Calling nested_loop_inner_widen
 #0 0x0000c894cca289cc llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/lib/Support/Unix/Signals.inc:804:13
 #1 0x0000c894cca23324 llvm::sys::RunSignalHandlers() /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/lib/Support/Signals.cpp:106:18
 #2 0x0000c894cca29bbc SignalHandler(int, siginfo_t*, void*) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/lib/Support/Unix/Signals.inc:0:3
 #3 0x0000f6898da4a8f8 (linux-vdso.so.1+0x8f8)
 #4 0x0000f6898d377608 (/lib/aarch64-linux-gnu/libc.so.6+0x87608)
 #5 0x0000f6898d32cb3c raise (/lib/aarch64-linux-gnu/libc.so.6+0x3cb3c)
 #6 0x0000f6898d317e00 abort (/lib/aarch64-linux-gnu/libc.so.6+0x27e00)
 #7 0x0000c894c5e77fec __sanitizer::Atexit(void (*)()) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp:168:10
 #8 0x0000c894c5e76680 __sanitizer::Die() /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_termination.cpp:52:5
 #9 0x0000c894c5e69650 Unlock /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/../sanitizer_common/sanitizer_mutex.h:250:16
#10 0x0000c894c5e69650 ~GenericScopedLock /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/../sanitizer_common/sanitizer_mutex.h:386:51
#11 0x0000c894c5e69650 __hwasan::ScopedReport::~ScopedReport() /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/hwasan_report.cpp:54:5
#12 0x0000c894c5e68de0 __hwasan::(anonymous namespace)::BaseReport::~BaseReport() /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/hwasan_report.cpp:476:7
#13 0x0000c894c5e66b74 __hwasan::ReportTagMismatch(__sanitizer::StackTrace*, unsigned long, unsigned long, bool, bool, unsigned long*) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/hwasan_report.cpp:1091:1
#14 0x0000c894c5e52cf8 Destroy /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/../sanitizer_common/sanitizer_common.h:532:31
#15 0x0000c894c5e52cf8 ~InternalMmapVector /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/../sanitizer_common/sanitizer_common.h:642:56
#16 0x0000c894c5e52cf8 __hwasan::HandleTagMismatch(__hwasan::AccessInfo, unsigned long, unsigned long, void*, unsigned long*) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/hwasan.cpp:245:1
#17 0x0000c894c5e551c8 __hwasan_tag_mismatch4 /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/hwasan/hwasan.cpp:764:1
#18 0x0000c894c5e6a2f8 __interception::InterceptFunction(char const*, unsigned long*, unsigned long, unsigned long) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/compiler-rt/lib/interception/interception_linux.cpp:60:0
#19 0x0000c894d166f664 getBlock /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h:217:45
#20 0x0000c894d166f664 getCFGElementRef /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h:230:59
#21 0x0000c894d166f664 clang::ento::ExprEngine::processCFGBlockEntrance(clang::BlockEdge const&, clang::ento::NodeBuilderWithSinks&, clang::ento::ExplodedNode*) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp:2570:45
#22 0x0000c894d15f3a1c hasGeneratedNodes /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h:333:37
#23 0x0000c894d15f3a1c clang::ento::CoreEngine::HandleBlockEdge(clang::BlockEdge const&, clang::ento::ExplodedNode*) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp:319:20
#24 0x0000c894d15f2c34 clang::ento::CoreEngine::dispatchWorkItem(clang::ento::ExplodedNode*, clang::ProgramPoint, clang::ento::WorkListUnit const&) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp:220:7
#25 0x0000c894d15f2398 operator-> /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_install_hwasan/include/c++/v1/__memory/unique_ptr.h:267:101
#26 0x0000c894d15f2398 clang::ento::CoreEngine::ExecuteWorkList(clang::LocationContext const*, unsigned int, llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>)::$_0::operator()(unsigned int) const /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp:140:12
#27 0x0000c894d15f14b4 clang::ento::CoreEngine::ExecuteWorkList(clang::LocationContext const*, unsigned int, llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp:165:7
#28 0x0000c894d0ebb9dc release /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h:232:9
#29 0x0000c894d0ebb9dc ~IntrusiveRefCntPtr /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h:196:27
#30 0x0000c894d0ebb9dc ExecuteWorkList /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h:192:5
#31 0x0000c894d0ebb9dc RunPathSensitiveChecks /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:772:7
#32 0x0000c894d0ebb9dc (anonymous namespace)::AnalysisConsumer::HandleCode(clang::Decl*, unsigned int, clang::ento::ExprEngine::InliningModes, llvm::DenseSet<clang::Decl const*, llvm::DenseMapInfo<clang::Decl const*, void>>*) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:741:5
#33 0x0000c894d0eb6ee4 begin /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/include/llvm/ADT/DenseMap.h:0:0
#34 0x0000c894d0eb6ee4 begin /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/include/llvm/ADT/DenseSet.h:187:45
#35 0x0000c894d0eb6ee4 HandleDeclsCallGraph /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:516:29
#36 0x0000c894d0eb6ee4 runAnalysisOnTranslationUnit /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:584:5
#37 0x0000c894d0eb6ee4 (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:647:3
#38 0x0000c894d18a7a38 clang::ParseAST(clang::Sema&, bool, bool) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/Parse/ParseAST.cpp:0:13
#39 0x0000c894ce81ed70 clang::FrontendAction::Execute() /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1231:10
#40 0x0000c894ce6f2144 getPtr /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/include/llvm/Support/Error.h:278:42
#41 0x0000c894ce6f2144 operator bool /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/include/llvm/Support/Error.h:241:16
#42 0x0000c894ce6f2144 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1058:23
#43 0x0000c894cea718cc operator-> /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_install_hwasan/include/c++/v1/__memory/shared_ptr.h:635:12
#44 0x0000c894cea718cc getFrontendOpts /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/include/clang/Frontend/CompilerInstance.h:307:12
#45 0x0000c894cea718cc clang::ExecuteCompilerInvocation(clang::CompilerInstance*) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:301:14
#46 0x0000c894c5e9cf28 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/tools/driver/cc1_main.cpp:294:15
#47 0x0000c894c5e92a9c ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/tools/driver/driver.cpp:223:12
#48 0x0000c894c5e902ac clang_main(int, char**, llvm::ToolContext const&) /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/tools/driver/driver.cpp:0:12
#49 0x0000c894c5eb2e34 main /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/tools/clang/tools/driver/clang-driver.cpp:17:3
#50 0x0000f6898d3184c4 (/lib/aarch64-linux-gnu/libc.so.6+0x284c4)
#51 0x0000f6898d318598 __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x28598)
#52 0x0000c894c5e52a30 _start (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/bin/clang+0x6512a30)
/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/tools/clang/test/Analysis/Output/loop-widening.c.script: line 2: 2870204 Aborted                 /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/bin/clang -cc1 -internal-isystem /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build_hwasan/lib/clang/21/include -nostdsysteminc -analyze -analyzer-constraints=range -setup-static-analyzer -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify -analyzer-config eagerly-assume=false /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/test/Analysis/loop-widening.c
```
2025-04-25 11:56:38 +02:00

687 lines
23 KiB
C++

//= ProgramState.cpp - Path-Sensitive "State" for tracking values --*- 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 implements ProgramState and ProgramStateManager.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/JsonSupport.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
using namespace clang;
using namespace ento;
namespace clang { namespace ento {
/// Increments the number of times this state is referenced.
void ProgramStateRetain(const ProgramState *state) {
++const_cast<ProgramState*>(state)->refCount;
}
/// Decrement the number of times this state is referenced.
void ProgramStateRelease(const ProgramState *state) {
assert(state->refCount > 0);
ProgramState *s = const_cast<ProgramState*>(state);
if (--s->refCount == 0) {
ProgramStateManager &Mgr = s->getStateManager();
Mgr.StateSet.RemoveNode(s);
s->~ProgramState();
Mgr.freeStates.push_back(s);
}
}
}}
ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env,
StoreRef st, GenericDataMap gdm)
: stateMgr(mgr),
Env(env),
store(st.getStore()),
GDM(gdm),
refCount(0) {
stateMgr->getStoreManager().incrementReferenceCount(store);
}
ProgramState::ProgramState(const ProgramState &RHS)
: stateMgr(RHS.stateMgr), Env(RHS.Env), store(RHS.store), GDM(RHS.GDM),
PosteriorlyOverconstrained(RHS.PosteriorlyOverconstrained), refCount(0) {
stateMgr->getStoreManager().incrementReferenceCount(store);
}
ProgramState::~ProgramState() {
if (store)
stateMgr->getStoreManager().decrementReferenceCount(store);
}
int64_t ProgramState::getID() const {
return getStateManager().Alloc.identifyKnownAlignedObject<ProgramState>(this);
}
ProgramStateManager::ProgramStateManager(ASTContext &Ctx,
StoreManagerCreator CreateSMgr,
ConstraintManagerCreator CreateCMgr,
llvm::BumpPtrAllocator &alloc,
ExprEngine *ExprEng)
: Eng(ExprEng), EnvMgr(alloc), GDMFactory(alloc),
svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {
StoreMgr = (*CreateSMgr)(*this);
ConstraintMgr = (*CreateCMgr)(*this, ExprEng);
}
ProgramStateManager::~ProgramStateManager() {
for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end();
I!=E; ++I)
I->second.second(I->second.first);
}
ProgramStateRef ProgramStateManager::removeDeadBindingsFromEnvironmentAndStore(
ProgramStateRef state, const StackFrameContext *LCtx,
SymbolReaper &SymReaper) {
// This code essentially performs a "mark-and-sweep" of the VariableBindings.
// The roots are any Block-level exprs and Decls that our liveness algorithm
// tells us are live. We then see what Decls they may reference, and keep
// those around. This code more than likely can be made faster, and the
// frequency of which this method is called should be experimented with
// for optimum performance.
ProgramState NewState = *state;
NewState.Env = EnvMgr.removeDeadBindings(NewState.Env, SymReaper, state);
// Clean up the store.
StoreRef newStore = StoreMgr->removeDeadBindings(NewState.getStore(), LCtx,
SymReaper);
NewState.setStore(newStore);
SymReaper.setReapedStore(newStore);
return getPersistentState(NewState);
}
ProgramStateRef ProgramState::bindLoc(Loc LV,
SVal V,
const LocationContext *LCtx,
bool notifyChanges) const {
ProgramStateManager &Mgr = getStateManager();
ExprEngine &Eng = Mgr.getOwningEngine();
ProgramStateRef State = makeWithStore(Mgr.StoreMgr->Bind(getStore(), LV, V));
const MemRegion *MR = LV.getAsRegion();
if (MR && notifyChanges)
return Eng.processRegionChange(State, MR, LCtx);
return State;
}
ProgramStateRef
ProgramState::bindDefaultInitial(SVal loc, SVal V,
const LocationContext *LCtx) const {
ProgramStateManager &Mgr = getStateManager();
const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();
BindResult BindRes = Mgr.StoreMgr->BindDefaultInitial(getStore(), R, V);
ProgramStateRef State = makeWithStore(BindRes);
return Mgr.getOwningEngine().processRegionChange(State, R, LCtx);
}
ProgramStateRef
ProgramState::bindDefaultZero(SVal loc, const LocationContext *LCtx) const {
ProgramStateManager &Mgr = getStateManager();
const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();
BindResult BindRes = Mgr.StoreMgr->BindDefaultZero(getStore(), R);
ProgramStateRef State = makeWithStore(BindRes);
return Mgr.getOwningEngine().processRegionChange(State, R, LCtx);
}
typedef ArrayRef<const MemRegion *> RegionList;
typedef ArrayRef<SVal> ValueList;
ProgramStateRef ProgramState::invalidateRegions(
RegionList Regions, const Stmt *S, unsigned Count,
const LocationContext *LCtx, bool CausedByPointerEscape,
InvalidatedSymbols *IS, const CallEvent *Call,
RegionAndSymbolInvalidationTraits *ITraits) const {
SmallVector<SVal, 8> Values;
for (const MemRegion *Reg : Regions)
Values.push_back(loc::MemRegionVal(Reg));
return invalidateRegions(Values, S, Count, LCtx, CausedByPointerEscape, IS,
Call, ITraits);
}
ProgramStateRef ProgramState::invalidateRegions(
ValueList Values, const Stmt *S, unsigned Count,
const LocationContext *LCtx, bool CausedByPointerEscape,
InvalidatedSymbols *IS, const CallEvent *Call,
RegionAndSymbolInvalidationTraits *ITraits) const {
ProgramStateManager &Mgr = getStateManager();
ExprEngine &Eng = Mgr.getOwningEngine();
InvalidatedSymbols InvalidatedSyms;
if (!IS)
IS = &InvalidatedSyms;
RegionAndSymbolInvalidationTraits ITraitsLocal;
if (!ITraits)
ITraits = &ITraitsLocal;
StoreManager::InvalidatedRegions TopLevelInvalidated;
StoreManager::InvalidatedRegions Invalidated;
const StoreRef &NewStore = Mgr.StoreMgr->invalidateRegions(
getStore(), Values, S, Count, LCtx, Call, *IS, *ITraits,
&TopLevelInvalidated, &Invalidated);
ProgramStateRef NewState = makeWithStore(NewStore);
if (CausedByPointerEscape) {
NewState = Eng.notifyCheckersOfPointerEscape(
NewState, IS, TopLevelInvalidated, Call, *ITraits);
}
return Eng.processRegionChanges(NewState, IS, TopLevelInvalidated,
Invalidated, LCtx, Call);
}
ProgramStateRef ProgramState::killBinding(Loc LV) const {
Store OldStore = getStore();
const StoreRef &newStore =
getStateManager().StoreMgr->killBinding(OldStore, LV);
if (newStore.getStore() == OldStore)
return this;
return makeWithStore(newStore);
}
/// We should never form a MemRegion that would wrap a TypedValueRegion of a
/// reference type. What we actually wanted was to create a MemRegion refering
/// to the pointee of that reference.
SVal ProgramState::desugarReference(SVal Val) const {
const auto *TyReg = dyn_cast_or_null<TypedValueRegion>(Val.getAsRegion());
if (!TyReg || !TyReg->getValueType()->isReferenceType())
return Val;
return getSVal(TyReg);
}
/// SymbolicRegions are expected to be wrapped by an ElementRegion as a
/// canonical representation. As a canonical representation, SymbolicRegions
/// should be wrapped by ElementRegions before getting a FieldRegion.
/// See f8643a9b31c4029942f67d4534c9139b45173504 why.
SVal ProgramState::wrapSymbolicRegion(SVal Val) const {
const auto *BaseReg = dyn_cast_or_null<SymbolicRegion>(Val.getAsRegion());
if (!BaseReg)
return Val;
StoreManager &SM = getStateManager().getStoreManager();
QualType ElemTy = BaseReg->getPointeeStaticType();
return loc::MemRegionVal{SM.GetElementZeroRegion(BaseReg, ElemTy)};
}
ProgramStateRef
ProgramState::enterStackFrame(const CallEvent &Call,
const StackFrameContext *CalleeCtx) const {
return makeWithStore(
getStateManager().StoreMgr->enterStackFrame(getStore(), Call, CalleeCtx));
}
SVal ProgramState::getSelfSVal(const LocationContext *LCtx) const {
const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
if (!SelfDecl)
return SVal();
return getSVal(getRegion(SelfDecl, LCtx));
}
SVal ProgramState::getSValAsScalarOrLoc(const MemRegion *R) const {
// We only want to do fetches from regions that we can actually bind
// values. For example, SymbolicRegions of type 'id<...>' cannot
// have direct bindings (but their can be bindings on their subregions).
if (!R->isBoundable())
return UnknownVal();
if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
QualType T = TR->getValueType();
if (Loc::isLocType(T) || T->isIntegralOrEnumerationType())
return getSVal(R);
}
return UnknownVal();
}
SVal ProgramState::getSVal(Loc location, QualType T) const {
SVal V = getRawSVal(location, T);
// If 'V' is a symbolic value that is *perfectly* constrained to
// be a constant value, use that value instead to lessen the burden
// on later analysis stages (so we have less symbolic values to reason
// about).
// We only go into this branch if we can convert the APSInt value we have
// to the type of T, which is not always the case (e.g. for void).
if (!T.isNull() && (T->isIntegralOrEnumerationType() || Loc::isLocType(T))) {
if (SymbolRef sym = V.getAsSymbol()) {
if (const llvm::APSInt *Int = getStateManager()
.getConstraintManager()
.getSymVal(this, sym)) {
// FIXME: Because we don't correctly model (yet) sign-extension
// and truncation of symbolic values, we need to convert
// the integer value to the correct signedness and bitwidth.
//
// This shows up in the following:
//
// char foo();
// unsigned x = foo();
// if (x == 54)
// ...
//
// The symbolic value stored to 'x' is actually the conjured
// symbol for the call to foo(); the type of that symbol is 'char',
// not unsigned.
APSIntPtr NewV = getBasicVals().Convert(T, *Int);
if (V.getAs<Loc>())
return loc::ConcreteInt(NewV);
return nonloc::ConcreteInt(NewV);
}
}
}
return V;
}
ProgramStateRef ProgramState::BindExpr(const Stmt *S,
const LocationContext *LCtx,
SVal V, bool Invalidate) const{
Environment NewEnv =
getStateManager().EnvMgr.bindExpr(Env, EnvironmentEntry(S, LCtx), V,
Invalidate);
if (NewEnv == Env)
return this;
ProgramState NewSt = *this;
NewSt.Env = NewEnv;
return getStateManager().getPersistentState(NewSt);
}
[[nodiscard]] std::pair<ProgramStateRef, ProgramStateRef>
ProgramState::assumeInBoundDual(DefinedOrUnknownSVal Idx,
DefinedOrUnknownSVal UpperBound,
QualType indexTy) const {
if (Idx.isUnknown() || UpperBound.isUnknown())
return {this, this};
// Build an expression for 0 <= Idx < UpperBound.
// This is the same as Idx + MIN < UpperBound + MIN, if overflow is allowed.
// FIXME: This should probably be part of SValBuilder.
ProgramStateManager &SM = getStateManager();
SValBuilder &svalBuilder = SM.getSValBuilder();
ASTContext &Ctx = svalBuilder.getContext();
// Get the offset: the minimum value of the array index type.
BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
if (indexTy.isNull())
indexTy = svalBuilder.getArrayIndexType();
nonloc::ConcreteInt Min(BVF.getMinValue(indexTy));
// Adjust the index.
SVal newIdx = svalBuilder.evalBinOpNN(this, BO_Add,
Idx.castAs<NonLoc>(), Min, indexTy);
if (newIdx.isUnknownOrUndef())
return {this, this};
// Adjust the upper bound.
SVal newBound =
svalBuilder.evalBinOpNN(this, BO_Add, UpperBound.castAs<NonLoc>(),
Min, indexTy);
if (newBound.isUnknownOrUndef())
return {this, this};
// Build the actual comparison.
SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT, newIdx.castAs<NonLoc>(),
newBound.castAs<NonLoc>(), Ctx.IntTy);
if (inBound.isUnknownOrUndef())
return {this, this};
// Finally, let the constraint manager take care of it.
ConstraintManager &CM = SM.getConstraintManager();
return CM.assumeDual(this, inBound.castAs<DefinedSVal>());
}
ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
DefinedOrUnknownSVal UpperBound,
bool Assumption,
QualType indexTy) const {
std::pair<ProgramStateRef, ProgramStateRef> R =
assumeInBoundDual(Idx, UpperBound, indexTy);
return Assumption ? R.first : R.second;
}
ConditionTruthVal ProgramState::isNonNull(SVal V) const {
ConditionTruthVal IsNull = isNull(V);
if (IsNull.isUnderconstrained())
return IsNull;
return ConditionTruthVal(!IsNull.getValue());
}
ConditionTruthVal ProgramState::areEqual(SVal Lhs, SVal Rhs) const {
return stateMgr->getSValBuilder().areEqual(this, Lhs, Rhs);
}
ConditionTruthVal ProgramState::isNull(SVal V) const {
if (V.isZeroConstant())
return true;
if (V.isConstant())
return false;
SymbolRef Sym = V.getAsSymbol(/* IncludeBaseRegion */ true);
if (!Sym)
return ConditionTruthVal();
return getStateManager().ConstraintMgr->isNull(this, Sym);
}
ProgramStateRef ProgramStateManager::getInitialState(const LocationContext *InitLoc) {
ProgramState State(this,
EnvMgr.getInitialEnvironment(),
StoreMgr->getInitialStore(InitLoc),
GDMFactory.getEmptyMap());
return getPersistentState(State);
}
ProgramStateRef ProgramStateManager::getPersistentStateWithGDM(
ProgramStateRef FromState,
ProgramStateRef GDMState) {
ProgramState NewState(*FromState);
NewState.GDM = GDMState->GDM;
return getPersistentState(NewState);
}
ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {
llvm::FoldingSetNodeID ID;
State.Profile(ID);
void *InsertPos;
if (ProgramState *I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
return I;
ProgramState *newState = nullptr;
if (!freeStates.empty()) {
newState = freeStates.back();
freeStates.pop_back();
}
else {
newState = Alloc.Allocate<ProgramState>();
}
new (newState) ProgramState(State);
StateSet.InsertNode(newState, InsertPos);
return newState;
}
ProgramStateRef ProgramState::makeWithStore(const StoreRef &store) const {
ProgramState NewSt(*this);
NewSt.setStore(store);
return getStateManager().getPersistentState(NewSt);
}
ProgramStateRef ProgramState::makeWithStore(const BindResult &BindRes) const {
ExprEngine &Eng = getStateManager().getOwningEngine();
ProgramStateRef State = makeWithStore(BindRes.ResultingStore);
// We must always notify the checkers for failing binds because otherwise they
// may keep stale traits for these symbols.
// Eg., Malloc checker may report leaks if we failed to bind that symbol.
if (BindRes.FailedToBindValues.empty())
return State;
return Eng.escapeValues(State, BindRes.FailedToBindValues, PSK_EscapeOnBind);
}
ProgramStateRef ProgramState::cloneAsPosteriorlyOverconstrained() const {
ProgramState NewSt(*this);
NewSt.PosteriorlyOverconstrained = true;
return getStateManager().getPersistentState(NewSt);
}
void ProgramState::setStore(const StoreRef &newStore) {
Store newStoreStore = newStore.getStore();
if (newStoreStore)
stateMgr->getStoreManager().incrementReferenceCount(newStoreStore);
if (store)
stateMgr->getStoreManager().decrementReferenceCount(store);
store = newStoreStore;
}
SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const {
Base = desugarReference(Base);
Base = wrapSymbolicRegion(Base);
return getStateManager().StoreMgr->getLValueField(D, Base);
}
SVal ProgramState::getLValue(const IndirectFieldDecl *D, SVal Base) const {
StoreManager &SM = *getStateManager().StoreMgr;
Base = desugarReference(Base);
Base = wrapSymbolicRegion(Base);
// FIXME: This should work with `SM.getLValueField(D->getAnonField(), Base)`,
// but that would break some tests. There is probably a bug somewhere that it
// would expose.
for (const auto *I : D->chain()) {
Base = SM.getLValueField(cast<FieldDecl>(I), Base);
}
return Base;
}
//===----------------------------------------------------------------------===//
// State pretty-printing.
//===----------------------------------------------------------------------===//
void ProgramState::printJson(raw_ostream &Out, const LocationContext *LCtx,
const char *NL, unsigned int Space,
bool IsDot) const {
Indent(Out, Space, IsDot) << "\"program_state\": {" << NL;
++Space;
ProgramStateManager &Mgr = getStateManager();
// Print the store.
Mgr.getStoreManager().printJson(Out, getStore(), NL, Space, IsDot);
// Print out the environment.
Env.printJson(Out, Mgr.getContext(), LCtx, NL, Space, IsDot);
// Print out the constraints.
Mgr.getConstraintManager().printJson(Out, this, NL, Space, IsDot);
// Print out the tracked dynamic types.
printDynamicTypeInfoJson(Out, this, NL, Space, IsDot);
// Print checker-specific data.
Mgr.getOwningEngine().printJson(Out, this, LCtx, NL, Space, IsDot);
--Space;
Indent(Out, Space, IsDot) << '}';
}
void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LCtx,
unsigned int Space) const {
printJson(Out, LCtx, /*NL=*/"\\l", Space, /*IsDot=*/true);
}
LLVM_DUMP_METHOD void ProgramState::dump() const {
printJson(llvm::errs());
}
AnalysisManager& ProgramState::getAnalysisManager() const {
return stateMgr->getOwningEngine().getAnalysisManager();
}
//===----------------------------------------------------------------------===//
// Generic Data Map.
//===----------------------------------------------------------------------===//
void *const* ProgramState::FindGDM(void *K) const {
return GDM.lookup(K);
}
void*
ProgramStateManager::FindGDMContext(void *K,
void *(*CreateContext)(llvm::BumpPtrAllocator&),
void (*DeleteContext)(void*)) {
std::pair<void*, void (*)(void*)>& p = GDMContexts[K];
if (!p.first) {
p.first = CreateContext(Alloc);
p.second = DeleteContext;
}
return p.first;
}
ProgramStateRef ProgramStateManager::addGDM(ProgramStateRef St, void *Key, void *Data){
ProgramState::GenericDataMap M1 = St->getGDM();
ProgramState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data);
if (M1 == M2)
return St;
ProgramState NewSt = *St;
NewSt.GDM = M2;
return getPersistentState(NewSt);
}
ProgramStateRef ProgramStateManager::removeGDM(ProgramStateRef state, void *Key) {
ProgramState::GenericDataMap OldM = state->getGDM();
ProgramState::GenericDataMap NewM = GDMFactory.remove(OldM, Key);
if (NewM == OldM)
return state;
ProgramState NewState = *state;
NewState.GDM = NewM;
return getPersistentState(NewState);
}
bool ScanReachableSymbols::scan(nonloc::LazyCompoundVal val) {
bool wasVisited = !visited.insert(val.getCVData()).second;
if (wasVisited)
return true;
StoreManager &StoreMgr = state->getStateManager().getStoreManager();
// FIXME: We don't really want to use getBaseRegion() here because pointer
// arithmetic doesn't apply, but scanReachableSymbols only accepts base
// regions right now.
const MemRegion *R = val.getRegion()->getBaseRegion();
return StoreMgr.scanReachableSymbols(val.getStore(), R, *this);
}
bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
for (SVal V : val)
if (!scan(V))
return false;
return true;
}
bool ScanReachableSymbols::scan(const SymExpr *sym) {
for (SymbolRef SubSym : sym->symbols()) {
bool wasVisited = !visited.insert(SubSym).second;
if (wasVisited)
continue;
if (!visitor.VisitSymbol(SubSym))
return false;
}
return true;
}
bool ScanReachableSymbols::scan(SVal val) {
if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>())
return scan(X->getRegion());
if (std::optional<nonloc::LazyCompoundVal> X =
val.getAs<nonloc::LazyCompoundVal>())
return scan(*X);
if (std::optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())
return scan(X->getLoc());
if (SymbolRef Sym = val.getAsSymbol())
return scan(Sym);
if (std::optional<nonloc::CompoundVal> X = val.getAs<nonloc::CompoundVal>())
return scan(*X);
return true;
}
bool ScanReachableSymbols::scan(const MemRegion *R) {
if (isa<MemSpaceRegion>(R))
return true;
bool wasVisited = !visited.insert(R).second;
if (wasVisited)
return true;
if (!visitor.VisitMemRegion(R))
return false;
// If this is a symbolic region, visit the symbol for the region.
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
if (!visitor.VisitSymbol(SR->getSymbol()))
return false;
// If this is a subregion, also visit the parent regions.
if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
const MemRegion *Super = SR->getSuperRegion();
if (!scan(Super))
return false;
// When we reach the topmost region, scan all symbols in it.
if (isa<MemSpaceRegion>(Super)) {
StoreManager &StoreMgr = state->getStateManager().getStoreManager();
if (!StoreMgr.scanReachableSymbols(state->getStore(), SR, *this))
return false;
}
}
// Regions captured by a block are also implicitly reachable.
if (const BlockDataRegion *BDR = dyn_cast<BlockDataRegion>(R)) {
for (auto Var : BDR->referenced_vars()) {
if (!scan(Var.getCapturedRegion()))
return false;
}
}
return true;
}
bool ProgramState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {
ScanReachableSymbols S(this, visitor);
return S.scan(val);
}
bool ProgramState::scanReachableSymbols(
llvm::iterator_range<region_iterator> Reachable,
SymbolVisitor &visitor) const {
ScanReachableSymbols S(this, visitor);
for (const MemRegion *R : Reachable) {
if (!S.scan(R))
return false;
}
return true;
}