diff options
author | Balazs Benics <benicsbalazs@gmail.com> | 2025-04-25 11:56:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-25 11:56:38 +0200 |
commit | 6171e4b34b1c85c42baa31cb17dad1799f414688 (patch) | |
tree | 90f1b6ede7f7e212251d194dc9b5020c4f5d4214 /clang | |
parent | 067067580f35d897e5aa4dcf94e9f35173984254 (diff) | |
download | llvm-6171e4b34b1c85c42baa31cb17dad1799f414688.zip llvm-6171e4b34b1c85c42baa31cb17dad1799f414688.tar.gz llvm-6171e4b34b1c85c42baa31cb17dad1799f414688.tar.bz2 |
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
```
Diffstat (limited to 'clang')
41 files changed, 407 insertions, 496 deletions
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index e70c703..a7ff38c 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -122,8 +122,7 @@ public: return (Kind) x; } - void dumpToStream(llvm::raw_ostream &OS, - bool TerminateWithNewLine = true) const; + void dumpToStream(llvm::raw_ostream &OS) const; void dump() const { dumpToStream(llvm::errs()); @@ -696,11 +695,6 @@ class CFGBlock { void dump() const { dumpToStream(llvm::errs()); } - - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(Parent); - ID.AddInteger(Index); - } }; template <bool IsReverse, bool IsConst> class ElementRefIterator { @@ -1196,8 +1190,6 @@ public: } }; -using ConstCFGElementRef = CFGBlock::ConstCFGElementRef; - /// CFGCallback defines methods that should be called when a logical /// operator error is found when building the CFG. class CFGCallback { diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h index 6c1025e..519d2d5 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -19,7 +19,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/raw_ostream.h" namespace clang { @@ -30,13 +29,6 @@ private: ASTContext &ACtx; ProgramStateRef State; - std::string printCFGElementRef(ConstCFGElementRef Elem) { - std::string Str; - llvm::raw_string_ostream OS(Str); - Elem->dumpToStream(OS, /*TerminateWithNewLine=*/false); - return Str; - } - std::string printStmt(const Stmt *S) { std::string Str; llvm::raw_string_ostream OS(Str); @@ -122,8 +114,7 @@ public: std::string VisitSymbolConjured(const SymbolConjured *S) { return "symbol of type '" + S->getType().getAsString() + - "' conjured at CFG element '" + - printCFGElementRef(S->getCFGElementRef()) + "'"; + "' conjured at statement '" + printStmt(S->getStmt()) + "'"; } std::string VisitSymbolDerived(const SymbolDerived *S) { diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index 63ca3ef..bb33a69 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -151,8 +151,6 @@ public: return Pred->getSVal(S); } - ConstCFGElementRef getCFGElementRef() const { return Eng.getCFGElementRef(); } - /// Returns true if the value of \p E is greater than or equal to \p /// Val under unsigned comparison. bool isGreaterOrEqual(const Expr *E, unsigned long long Val); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 2851941..5f85525 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -226,7 +226,7 @@ public: return (*G.roots_begin())->getLocation().getLocationContext(); } - ConstCFGElementRef getCFGElementRef() const { + CFGBlock::ConstCFGElementRef getCFGElementRef() const { const CFGBlock *blockPtr = currBldrCtx ? currBldrCtx->getBlock() : nullptr; return {blockPtr, currStmtIdx}; } diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h index 50f2197..e75228f 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h @@ -27,8 +27,7 @@ namespace ento { /// by the loop body in any iteration. ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, const LocationContext *LCtx, - unsigned BlockCount, - ConstCFGElementRef Elem); + unsigned BlockCount, const Stmt *LoopStmt); } // end namespace ento } // end namespace clang diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 5271453..4d66e08 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -313,7 +313,7 @@ public: /// be triggered by this event. /// /// \param Regions the set of regions to be invalidated. - /// \param Elem The CFG Element that caused the invalidation. + /// \param E the expression that caused the invalidation. /// \param BlockCount The number of times the current basic block has been /// visited. /// \param CausesPointerEscape the flag is set to true when the invalidation @@ -325,17 +325,16 @@ public: /// \param ITraits information about special handling for particular regions /// or symbols. [[nodiscard]] ProgramStateRef - invalidateRegions(ArrayRef<const MemRegion *> Regions, - ConstCFGElementRef Elem, unsigned BlockCount, - const LocationContext *LCtx, bool CausesPointerEscape, - InvalidatedSymbols *IS = nullptr, + invalidateRegions(ArrayRef<const MemRegion *> Regions, const Stmt *S, + unsigned BlockCount, const LocationContext *LCtx, + bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, const CallEvent *Call = nullptr, RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; [[nodiscard]] ProgramStateRef - invalidateRegions(ArrayRef<SVal> Values, ConstCFGElementRef Elem, - unsigned BlockCount, const LocationContext *LCtx, - bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, + invalidateRegions(ArrayRef<SVal> Values, const Stmt *S, unsigned BlockCount, + const LocationContext *LCtx, bool CausesPointerEscape, + InvalidatedSymbols *IS = nullptr, const CallEvent *Call = nullptr, RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index bd5d245..54430d4 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -19,7 +19,6 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/Type.h" -#include "clang/Analysis/CFG.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" @@ -172,11 +171,19 @@ public: // Forwarding methods to SymbolManager. - const SymbolConjured *conjureSymbol(ConstCFGElementRef Elem, + const SymbolConjured* conjureSymbol(const Stmt *stmt, const LocationContext *LCtx, - QualType type, unsigned visitCount, + QualType type, + unsigned visitCount, const void *symbolTag = nullptr) { - return SymMgr.conjureSymbol(Elem, LCtx, type, visitCount, symbolTag); + return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag); + } + + const SymbolConjured* conjureSymbol(const Expr *expr, + const LocationContext *LCtx, + unsigned visitCount, + const void *symbolTag = nullptr) { + return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag); } /// Construct an SVal representing '0' for the specified type. @@ -192,19 +199,29 @@ public: /// preserve the relation between related(or even equivalent) expressions, so /// conjured symbols should be used sparingly. DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, - ConstCFGElementRef elem, + const Expr *expr, const LocationContext *LCtx, unsigned count); - DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, - ConstCFGElementRef elem, + DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Stmt *S, const LocationContext *LCtx, QualType type, unsigned count); - DefinedOrUnknownSVal conjureSymbolVal(ConstCFGElementRef elem, + DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt, const LocationContext *LCtx, - QualType type, unsigned visitCount); + QualType type, + unsigned visitCount); /// Conjure a symbol representing heap allocated memory region. - DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, + /// + /// Note, the expression should represent a location. + DefinedSVal getConjuredHeapSymbolVal(const Expr *E, + const LocationContext *LCtx, + unsigned Count); + + /// Conjure a symbol representing heap allocated memory region. + /// + /// Note, now, the expression *doesn't* need to represent a location. + /// But the type need to! + DefinedSVal getConjuredHeapSymbolVal(const Expr *E, const LocationContext *LCtx, QualType type, unsigned Count); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 29a53fc..cf7623c 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -14,13 +14,13 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H #include "clang/AST/Type.h" -#include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" @@ -223,7 +223,7 @@ public: /// /// \param[in] store The initial store. /// \param[in] Values The values to invalidate. - /// \param[in] Elem The current CFG Element being evaluated. Used to conjure + /// \param[in] S The current statement being evaluated. Used to conjure /// symbols to mark the values of invalidated regions. /// \param[in] Count The current block count. Used to conjure /// symbols to mark the values of invalidated regions. @@ -241,8 +241,8 @@ public: /// even if they do not currently have bindings. Pass \c NULL if this /// information will not be used. virtual StoreRef invalidateRegions( - Store store, ArrayRef<SVal> Values, ConstCFGElementRef Elem, - unsigned Count, const LocationContext *LCtx, const CallEvent *Call, + Store store, ArrayRef<SVal> Values, const Stmt *S, unsigned Count, + const LocationContext *LCtx, const CallEvent *Call, InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 0; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 9e7c98f..cbbea1b 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -80,62 +80,29 @@ public: /// A symbol representing the result of an expression in the case when we do /// not know anything about what the expression is. class SymbolConjured : public SymbolData { - ConstCFGElementRef Elem; + const Stmt *S; QualType T; unsigned Count; const LocationContext *LCtx; const void *SymbolTag; friend class SymExprAllocator; - SymbolConjured(SymbolID sym, ConstCFGElementRef elem, - const LocationContext *lctx, QualType t, unsigned count, - const void *symbolTag) - : SymbolData(SymbolConjuredKind, sym), Elem(elem), T(t), Count(count), + SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx, + QualType t, unsigned count, const void *symbolTag) + : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count), LCtx(lctx), SymbolTag(symbolTag) { + // FIXME: 's' might be a nullptr if we're conducting invalidation + // that was caused by a destructor call on a temporary object, + // which has no statement associated with it. + // Due to this, we might be creating the same invalidation symbol for + // two different invalidation passes (for two different temporaries). assert(lctx); assert(isValidTypeForSymbol(t)); } public: - ConstCFGElementRef getCFGElementRef() const { return Elem; } - - // It might return null. - const Stmt *getStmt() const { - switch (Elem->getKind()) { - case CFGElement::Initializer: - return Elem->castAs<CFGInitializer>().getInitializer()->getInit(); - case CFGElement::ScopeBegin: - return Elem->castAs<CFGScopeBegin>().getTriggerStmt(); - case CFGElement::ScopeEnd: - return Elem->castAs<CFGScopeEnd>().getTriggerStmt(); - case CFGElement::NewAllocator: - return Elem->castAs<CFGNewAllocator>().getAllocatorExpr(); - case CFGElement::LifetimeEnds: - return Elem->castAs<CFGLifetimeEnds>().getTriggerStmt(); - case CFGElement::LoopExit: - return Elem->castAs<CFGLoopExit>().getLoopStmt(); - case CFGElement::Statement: - return Elem->castAs<CFGStmt>().getStmt(); - case CFGElement::Constructor: - return Elem->castAs<CFGConstructor>().getStmt(); - case CFGElement::CXXRecordTypedCall: - return Elem->castAs<CFGCXXRecordTypedCall>().getStmt(); - case CFGElement::AutomaticObjectDtor: - return Elem->castAs<CFGAutomaticObjDtor>().getTriggerStmt(); - case CFGElement::DeleteDtor: - return Elem->castAs<CFGDeleteDtor>().getDeleteExpr(); - case CFGElement::BaseDtor: - return nullptr; - case CFGElement::MemberDtor: - return nullptr; - case CFGElement::TemporaryDtor: - return Elem->castAs<CFGTemporaryDtor>().getBindTemporaryExpr(); - case CFGElement::CleanupFunction: - return nullptr; - } - return nullptr; - } - + /// It might return null. + const Stmt *getStmt() const { return S; } unsigned getCount() const { return Count; } /// It might return null. const void *getTag() const { return SymbolTag; } @@ -146,11 +113,11 @@ public: void dumpToStream(raw_ostream &os) const override; - static void Profile(llvm::FoldingSetNodeID &profile, ConstCFGElementRef Elem, + static void Profile(llvm::FoldingSetNodeID &profile, const Stmt *S, const LocationContext *LCtx, QualType T, unsigned Count, const void *SymbolTag) { profile.AddInteger((unsigned)SymbolConjuredKind); - profile.Add(Elem); + profile.AddPointer(S); profile.AddPointer(LCtx); profile.Add(T); profile.AddInteger(Count); @@ -158,7 +125,7 @@ public: } void Profile(llvm::FoldingSetNodeID& profile) override { - Profile(profile, Elem, LCtx, T, Count, SymbolTag); + Profile(profile, S, LCtx, T, Count, SymbolTag); } // Implement isa<T> support. @@ -566,12 +533,18 @@ public: template <typename SymExprT, typename... Args> const SymExprT *acquire(Args &&...args); - const SymbolConjured *conjureSymbol(ConstCFGElementRef Elem, + const SymbolConjured *conjureSymbol(const Stmt *E, const LocationContext *LCtx, QualType T, unsigned VisitCount, const void *SymbolTag = nullptr) { + return acquire<SymbolConjured>(E, LCtx, T, VisitCount, SymbolTag); + } - return acquire<SymbolConjured>(Elem, LCtx, T, VisitCount, SymbolTag); + const SymbolConjured* conjureSymbol(const Expr *E, + const LocationContext *LCtx, + unsigned VisitCount, + const void *SymbolTag = nullptr) { + return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag); } QualType getType(const SymExpr *SE) const { diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 4b50b92..d03a0a54 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -5803,17 +5803,16 @@ static void print_construction_context(raw_ostream &OS, } static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, - const CFGElement &E, bool TerminateWithNewLine = true); + const CFGElement &E); -void CFGElement::dumpToStream(llvm::raw_ostream &OS, - bool TerminateWithNewLine) const { +void CFGElement::dumpToStream(llvm::raw_ostream &OS) const { LangOptions LangOpts; StmtPrinterHelper Helper(nullptr, LangOpts); - print_elem(OS, Helper, *this, TerminateWithNewLine); + print_elem(OS, Helper, *this); } static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, - const CFGElement &E, bool TerminateWithNewLine) { + const CFGElement &E) { switch (E.getKind()) { case CFGElement::Kind::Statement: case CFGElement::Kind::CXXRecordTypedCall: @@ -5830,9 +5829,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, if (Children.begin() != Children.end()) { OS << "({ ... ; "; Helper.handledStmt(*SE->getSubStmt()->body_rbegin(),OS); - OS << " })"; - if (TerminateWithNewLine) - OS << '\n'; + OS << " })\n"; return; } } @@ -5841,8 +5838,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, if (B->getOpcode() == BO_Comma) { OS << "... , "; Helper.handledStmt(B->getRHS(),OS); - if (TerminateWithNewLine) - OS << '\n'; + OS << '\n'; return; } } @@ -5870,14 +5866,15 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, } // Expressions need a newline. - if (isa<Expr>(S) && TerminateWithNewLine) + if (isa<Expr>(S)) OS << '\n'; - return; + break; } case CFGElement::Kind::Initializer: print_initializer(OS, Helper, E.castAs<CFGInitializer>().getInitializer()); + OS << '\n'; break; case CFGElement::Kind::AutomaticObjectDtor: { @@ -5891,44 +5888,43 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, OS << ".~"; T.getUnqualifiedType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << "() (Implicit destructor)"; + OS << "() (Implicit destructor)\n"; break; } case CFGElement::Kind::CleanupFunction: OS << "CleanupFunction (" - << E.castAs<CFGCleanupFunction>().getFunctionDecl()->getName() << ")"; + << E.castAs<CFGCleanupFunction>().getFunctionDecl()->getName() << ")\n"; break; case CFGElement::Kind::LifetimeEnds: Helper.handleDecl(E.castAs<CFGLifetimeEnds>().getVarDecl(), OS); - OS << " (Lifetime ends)"; + OS << " (Lifetime ends)\n"; break; case CFGElement::Kind::LoopExit: - OS << E.castAs<CFGLoopExit>().getLoopStmt()->getStmtClassName() - << " (LoopExit)"; + OS << E.castAs<CFGLoopExit>().getLoopStmt()->getStmtClassName() << " (LoopExit)\n"; break; case CFGElement::Kind::ScopeBegin: OS << "CFGScopeBegin("; if (const VarDecl *VD = E.castAs<CFGScopeBegin>().getVarDecl()) OS << VD->getQualifiedNameAsString(); - OS << ")"; + OS << ")\n"; break; case CFGElement::Kind::ScopeEnd: OS << "CFGScopeEnd("; if (const VarDecl *VD = E.castAs<CFGScopeEnd>().getVarDecl()) OS << VD->getQualifiedNameAsString(); - OS << ")"; + OS << ")\n"; break; case CFGElement::Kind::NewAllocator: OS << "CFGNewAllocator("; if (const CXXNewExpr *AllocExpr = E.castAs<CFGNewAllocator>().getAllocatorExpr()) AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << ")"; + OS << ")\n"; break; case CFGElement::Kind::DeleteDtor: { @@ -5940,14 +5936,14 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const_cast<CXXDeleteExpr*>(DE.getDeleteExpr()); Helper.handledStmt(cast<Stmt>(DelExpr->getArgument()), OS); OS << "->~" << RD->getName().str() << "()"; - OS << " (Implicit destructor)"; + OS << " (Implicit destructor)\n"; break; } case CFGElement::Kind::BaseDtor: { const CXXBaseSpecifier *BS = E.castAs<CFGBaseDtor>().getBaseSpecifier(); OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()"; - OS << " (Base object destructor)"; + OS << " (Base object destructor)\n"; break; } @@ -5956,7 +5952,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const Type *T = FD->getType()->getBaseElementTypeUnsafe(); OS << "this->" << FD->getName(); OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()"; - OS << " (Member object destructor)"; + OS << " (Member object destructor)\n"; break; } @@ -5965,12 +5961,10 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, E.castAs<CFGTemporaryDtor>().getBindTemporaryExpr(); OS << "~"; BT->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); - OS << "() (Temporary object destructor)"; + OS << "() (Temporary object destructor)\n"; break; } } - if (TerminateWithNewLine) - OS << '\n'; } static void print_block(raw_ostream &OS, const CFG* cfg, diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 49ca39f..39dcaf0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -273,29 +273,28 @@ public: /// Invalidate the destination buffer determined by characters copied. static ProgramStateRef invalidateDestinationBufferBySize(CheckerContext &C, ProgramStateRef S, - const Expr *BufE, ConstCFGElementRef Elem, - SVal BufV, SVal SizeV, QualType SizeTy); + const Expr *BufE, SVal BufV, SVal SizeV, + QualType SizeTy); /// Operation never overflows, do not invalidate the super region. static ProgramStateRef invalidateDestinationBufferNeverOverflows( - CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV); + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV); /// We do not know whether the operation can overflow (e.g. size is unknown), /// invalidate the super region and escape related pointers. static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion( - CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV); + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV); /// Invalidate the source buffer for escaping pointers. static ProgramStateRef invalidateSourceBuffer(CheckerContext &C, ProgramStateRef S, - ConstCFGElementRef Elem, - SVal BufV); + const Expr *BufE, SVal BufV); /// @param InvalidationTraitOperations Determine how to invlidate the /// MemRegion by setting the invalidation traits. Return true to cause pointer /// escape, or false otherwise. static ProgramStateRef invalidateBufferAux( - CheckerContext &C, ProgramStateRef State, ConstCFGElementRef Elem, SVal V, + CheckerContext &C, ProgramStateRef State, const Expr *Ex, SVal V, llvm::function_ref<bool(RegionAndSymbolInvalidationTraits &, const MemRegion *)> InvalidationTraitOperations); @@ -303,8 +302,8 @@ public: static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, const MemRegion *MR); - static bool memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, - SVal CharE, const Expr *Size, CheckerContext &C, + static bool memsetAux(const Expr *DstBuffer, SVal CharE, + const Expr *Size, CheckerContext &C, ProgramStateRef &State); // Re-usable checks @@ -1212,8 +1211,8 @@ bool CStringChecker::isFirstBufInBound(CheckerContext &C, ProgramStateRef State, } ProgramStateRef CStringChecker::invalidateDestinationBufferBySize( - CheckerContext &C, ProgramStateRef S, const Expr *BufE, - ConstCFGElementRef Elem, SVal BufV, SVal SizeV, QualType SizeTy) { + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV, + SVal SizeV, QualType SizeTy) { auto InvalidationTraitOperations = [&C, S, BufTy = BufE->getType(), BufV, SizeV, SizeTy](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { @@ -1228,22 +1227,22 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferBySize( return false; }; - return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion( - CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV) { + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &, const MemRegion *R) { return isa<FieldRegion>(R); }; - return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows( - CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV) { + CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { if (MemRegion::FieldRegionKind == R->getKind()) @@ -1253,12 +1252,12 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows( return false; }; - return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C, ProgramStateRef S, - ConstCFGElementRef Elem, + const Expr *BufE, SVal BufV) { auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) { @@ -1270,11 +1269,11 @@ ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C, return true; }; - return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations); + return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations); } ProgramStateRef CStringChecker::invalidateBufferAux( - CheckerContext &C, ProgramStateRef State, ConstCFGElementRef Elem, SVal V, + CheckerContext &C, ProgramStateRef State, const Expr *E, SVal V, llvm::function_ref<bool(RegionAndSymbolInvalidationTraits &, const MemRegion *)> InvalidationTraitOperations) { @@ -1300,7 +1299,7 @@ ProgramStateRef CStringChecker::invalidateBufferAux( RegionAndSymbolInvalidationTraits ITraits; bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R); - return State->invalidateRegions(R, Elem, C.blockCount(), LCtx, + return State->invalidateRegions(R, E, C.blockCount(), LCtx, CausesPointerEscape, nullptr, nullptr, &ITraits); } @@ -1350,9 +1349,9 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, } } -bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, - SVal CharVal, const Expr *Size, - CheckerContext &C, ProgramStateRef &State) { +bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, + const Expr *Size, CheckerContext &C, + ProgramStateRef &State) { SVal MemVal = C.getSVal(DstBuffer); SVal SizeVal = C.getSVal(Size); const MemRegion *MR = MemVal.getAsRegion(); @@ -1405,8 +1404,8 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, } else { // If the destination buffer's extent is not equal to the value of // third argument, just invalidate buffer. - State = invalidateDestinationBufferBySize( - C, State, DstBuffer, Elem, MemVal, SizeVal, Size->getType()); + State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal, + SizeVal, Size->getType()); } if (StateNullChar && !StateNonNullChar) { @@ -1431,7 +1430,7 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem, } else { // If the offset is not zero and char value is not concrete, we can do // nothing but invalidate the buffer. - State = invalidateDestinationBufferBySize(C, State, DstBuffer, Elem, MemVal, + State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal, SizeVal, Size->getType()); } return true; @@ -1516,8 +1515,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call, // conjure a return value for later. if (lastElement.isUnknown()) lastElement = C.getSValBuilder().conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, - C.blockCount()); + nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); // The byte after the last byte copied is the return value. state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement); @@ -1534,12 +1532,12 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call, // This would probably remove any existing bindings past the end of the // copied region, but that's still an improvement over blank invalidation. state = invalidateDestinationBufferBySize( - C, state, Dest.Expression, Call.getCFGElementRef(), - C.getSVal(Dest.Expression), sizeVal, Size.Expression->getType()); + C, state, Dest.Expression, C.getSVal(Dest.Expression), sizeVal, + Size.Expression->getType()); // Invalidate the source (const-invalidation without const-pointer-escaping // the address of the top-level region). - state = invalidateSourceBuffer(C, state, Call.getCFGElementRef(), + state = invalidateSourceBuffer(C, state, Source.Expression, C.getSVal(Source.Expression)); C.addTransition(state); @@ -1667,8 +1665,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call, State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK); if (State) { // The return value is the comparison result, which we don't know. - SVal CmpV = Builder.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, + C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV); C.addTransition(State); } @@ -1772,7 +1770,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // All we know is the return value is the min of the string length // and the limit. This is better than nothing. result = C.getSValBuilder().conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); NonLoc resultNL = result.castAs<NonLoc>(); if (strLengthNL) { @@ -1796,7 +1794,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // value, so it can be used in constraints, at least. if (result.isUnknown()) { result = C.getSValBuilder().conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); } } @@ -2237,13 +2235,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call, // can use LazyCompoundVals to copy the source values into the destination. // This would probably remove any existing bindings past the end of the // string, but that's still an improvement over blank invalidation. - state = invalidateDestinationBufferBySize( - C, state, Dst.Expression, Call.getCFGElementRef(), *dstRegVal, - amountCopied, C.getASTContext().getSizeType()); + state = invalidateDestinationBufferBySize(C, state, Dst.Expression, + *dstRegVal, amountCopied, + C.getASTContext().getSizeType()); // Invalidate the source (const-invalidation without const-pointer-escaping // the address of the top-level region). - state = invalidateSourceBuffer(C, state, Call.getCFGElementRef(), srcVal); + state = invalidateSourceBuffer(C, state, srcExpr.Expression, srcVal); // Set the C string length of the destination, if we know it. if (IsBounded && (appendK == ConcatFnKind::none)) { @@ -2263,8 +2261,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call, // If this is a stpcpy-style copy, but we were unable to check for a buffer // overflow, we still need a result. Conjure a return value. if (ReturnEnd && Result.isUnknown()) { - Result = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, + C.blockCount()); } } // Set the return value. @@ -2363,8 +2361,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call, const StringLiteral *RightStrLiteral = getCStringLiteral(C, state, Right.Expression, RightVal); bool canComputeResult = false; - SVal resultVal = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), + LCtx, C.blockCount()); if (LeftStrLiteral && RightStrLiteral) { StringRef LeftStrRef = LeftStrLiteral->getString(); @@ -2465,20 +2463,20 @@ void CStringChecker::evalStrsep(CheckerContext &C, // character to NUL. // As the replacement never overflows, do not invalidate its super region. State = invalidateDestinationBufferNeverOverflows( - C, State, Call.getCFGElementRef(), Result); + C, State, SearchStrPtr.Expression, Result); // Overwrite the search string pointer. The new value is either an address // further along in the same string, or NULL if there are no more tokens. State = State->bindLoc(*SearchStrLoc, - SVB.conjureSymbolVal(getTag(), Call.getCFGElementRef(), + SVB.conjureSymbolVal(getTag(), Call.getOriginExpr(), LCtx, CharPtrTy, C.blockCount()), LCtx); } else { assert(SearchStrVal.isUnknown()); // Conjure a symbolic value. It's the best we can do. - Result = SVB.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, + C.blockCount()); } // Set the return value, and finish. @@ -2516,13 +2514,13 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C, SVal DstVal = State->getSVal(Dst, LCtx); // FIXME: As we do not know how many items are copied, we also invalidate the // super region containing the target location. - State = invalidateDestinationBufferAlwaysEscapeSuperRegion( - C, State, Call.getCFGElementRef(), DstVal); + State = + invalidateDestinationBufferAlwaysEscapeSuperRegion(C, State, Dst, DstVal); SValBuilder &SVB = C.getSValBuilder(); - SVal ResultVal = SVB.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); + SVal ResultVal = + SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal); C.addTransition(State); @@ -2571,8 +2569,8 @@ void CStringChecker::evalMemset(CheckerContext &C, // According to the values of the arguments, bind the value of the second // argument to the destination buffer and set string length, or just // invalidate the destination buffer. - if (!memsetAux(Buffer.Expression, Call.getCFGElementRef(), - C.getSVal(CharE.Expression), Size.Expression, C, State)) + if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression), + Size.Expression, C, State)) return; State = State->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal); @@ -2616,8 +2614,7 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallEvent &Call) const { if (!State) return; - if (!memsetAux(Buffer.Expression, Call.getCFGElementRef(), Zero, - Size.Expression, C, State)) + if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State)) return; C.addTransition(State); diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp index 3cc49e4..d850344 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp @@ -33,11 +33,11 @@ namespace { class ContainerModeling : public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> { - void handleBegin(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, + void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Cont) const; - void handleEnd(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, + void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Cont) const; - void handleAssignment(CheckerContext &C, SVal Cont, ConstCFGElementRef Elem, + void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr, SVal OldCont = UndefinedVal()) const; void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const; void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const; @@ -108,12 +108,11 @@ bool backModifiable(ProgramStateRef State, const MemRegion *Reg); SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont); SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont); ProgramStateRef createContainerBegin(ProgramStateRef State, - const MemRegion *Cont, - ConstCFGElementRef Elem, QualType T, - const LocationContext *LCtx, + const MemRegion *Cont, const Expr *E, + QualType T, const LocationContext *LCtx, unsigned BlockCount); ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, - ConstCFGElementRef Elem, QualType T, + const Expr *E, QualType T, const LocationContext *LCtx, unsigned BlockCount); ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, @@ -164,12 +163,12 @@ void ContainerModeling::checkPostCall(const CallEvent &Call, return; if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) { - handleAssignment(C, InstCall->getCXXThisVal(), Call.getCFGElementRef(), - Call.getArgSVal(0)); + handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), + Call.getArgSVal(0)); return; } - handleAssignment(C, InstCall->getCXXThisVal(), C.getCFGElementRef()); + handleAssignment(C, InstCall->getCXXThisVal()); return; } } else { @@ -199,13 +198,13 @@ void ContainerModeling::checkPostCall(const CallEvent &Call, return; if (isBeginCall(Func)) { - handleBegin(C, Call.getCFGElementRef(), Call.getReturnValue(), + handleBegin(C, OrigExpr, Call.getReturnValue(), InstCall->getCXXThisVal()); return; } if (isEndCall(Func)) { - handleEnd(C, Call.getCFGElementRef(), Call.getReturnValue(), + handleEnd(C, OrigExpr, Call.getReturnValue(), InstCall->getCXXThisVal()); return; } @@ -251,8 +250,8 @@ void ContainerModeling::checkDeadSymbols(SymbolReaper &SR, C.addTransition(State); } -void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem, - SVal RetVal, SVal Cont) const { +void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, + SVal RetVal, SVal Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -264,7 +263,7 @@ void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem, auto State = C.getState(); auto BeginSym = getContainerBegin(State, ContReg); if (!BeginSym) { - State = createContainerBegin(State, ContReg, Elem, C.getASTContext().LongTy, + State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy, C.getLocationContext(), C.blockCount()); BeginSym = getContainerBegin(State, ContReg); } @@ -273,8 +272,8 @@ void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem, C.addTransition(State); } -void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem, - SVal RetVal, SVal Cont) const { +void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, + SVal RetVal, SVal Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -286,7 +285,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem, auto State = C.getState(); auto EndSym = getContainerEnd(State, ContReg); if (!EndSym) { - State = createContainerEnd(State, ContReg, Elem, C.getASTContext().LongTy, + State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy, C.getLocationContext(), C.blockCount()); EndSym = getContainerEnd(State, ContReg); } @@ -296,8 +295,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem, } void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont, - ConstCFGElementRef Elem, - SVal OldCont) const { + const Expr *CE, SVal OldCont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -331,7 +329,7 @@ void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont, auto &SVB = C.getSValBuilder(); // Then generate and assign a new "end" symbol for the new container. auto NewEndSym = - SymMgr.conjureSymbol(Elem, C.getLocationContext(), + SymMgr.conjureSymbol(CE, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = assumeNoOverflow(State, NewEndSym, 4); if (CData) { @@ -850,9 +848,8 @@ SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) { } ProgramStateRef createContainerBegin(ProgramStateRef State, - const MemRegion *Cont, - ConstCFGElementRef Elem, QualType T, - const LocationContext *LCtx, + const MemRegion *Cont, const Expr *E, + QualType T, const LocationContext *LCtx, unsigned BlockCount) { // Only create if it does not exist const auto *CDataPtr = getContainerData(State, Cont); @@ -860,8 +857,8 @@ ProgramStateRef createContainerBegin(ProgramStateRef State, return State; auto &SymMgr = State->getSymbolManager(); - const SymbolConjured *Sym = - SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "begin"); + const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, + "begin"); State = assumeNoOverflow(State, Sym, 4); if (CDataPtr) { @@ -874,7 +871,7 @@ ProgramStateRef createContainerBegin(ProgramStateRef State, } ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, - ConstCFGElementRef Elem, QualType T, + const Expr *E, QualType T, const LocationContext *LCtx, unsigned BlockCount) { // Only create if it does not exist @@ -883,8 +880,8 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, return State; auto &SymMgr = State->getSymbolManager(); - const SymbolConjured *Sym = - SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "end"); + const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, + "end"); State = assumeNoOverflow(State, Sym, 4); if (CDataPtr) { diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp index abfc5d2..6ffc05f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp @@ -124,7 +124,7 @@ void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { // of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker // object. const SymbolConjured *Sym = SVB.conjureSymbol( - C.getCFGElementRef(), C.getLocationContext(), + nullptr, C.getLocationContext(), ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl); // The symbolic region is untyped, create a typed sub-region in it. @@ -256,11 +256,11 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, CheckerContext &C, - ConstCFGElementRef Elem) { + const Expr *InvalE) { const MemRegion *ErrnoR = State->get<ErrnoRegion>(); if (!ErrnoR) return State; - State = State->invalidateRegions(ErrnoR, Elem, C.blockCount(), + State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(), C.getLocationContext(), false); if (!State) return nullptr; diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h index e414353..95da8a2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h @@ -96,10 +96,9 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, /// Set errno state for the common case when a standard function indicates /// failure only by \c errno. Sets \c ErrnoCheckState to \c MustBeChecked, and /// invalidates the errno region (clear of previous value). -/// \arg \c Elem CFG Element that causes invalidation of \c errno. +/// \arg \c InvalE Expression that causes invalidation of \c errno. ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, - CheckerContext &C, - ConstCFGElementRef Elem); + CheckerContext &C, const Expr *InvalE); } // namespace errno_modeling } // namespace ento diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp index be70819..6076a6b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp @@ -131,8 +131,7 @@ void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C, ProgramStateRef StateFailure = State->BindExpr( Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal( - /*symbolTag=*/nullptr, Call.getCFGElementRef(), C.getLocationContext(), - C.blockCount()); + nullptr, Call.getOriginExpr(), C.getLocationContext(), C.blockCount()); StateFailure = StateFailure->assume(ErrnoVal, true); assert(StateFailure && "Failed to assume on an initial value."); StateFailure = diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp index e9825b7..ba561dd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp @@ -207,15 +207,14 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val, } ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val, - const MemRegion *Cont, - ConstCFGElementRef Elem, + const MemRegion *Cont, const Stmt *S, const LocationContext *LCtx, unsigned blockCount) { auto &StateMgr = State->getStateManager(); auto &SymMgr = StateMgr.getSymbolManager(); auto &ACtx = StateMgr.getContext(); - auto *Sym = SymMgr.conjureSymbol(Elem, LCtx, ACtx.LongTy, blockCount); + auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount); State = assumeNoOverflow(State, Sym, 4); return setIteratorPosition(State, Val, IteratorPosition::getPosition(Cont, Sym)); diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.h b/clang/lib/StaticAnalyzer/Checkers/Iterator.h index 0a26db0..46de8ea 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.h +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h @@ -165,8 +165,7 @@ const IteratorPosition *getIteratorPosition(ProgramStateRef State, SVal Val); ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val, const IteratorPosition &Pos); ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val, - const MemRegion *Cont, - ConstCFGElementRef Elem, + const MemRegion *Cont, const Stmt *S, const LocationContext *LCtx, unsigned blockCount); ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter, diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp index 6139585..d4ce73b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -90,9 +90,8 @@ class IteratorModeling check::PostStmt<MaterializeTemporaryExpr>, check::Bind, check::LiveSymbols, check::DeadSymbols> { - using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, - ConstCFGElementRef, SVal, SVal, - SVal) const; + using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *, + SVal, SVal, SVal) const; void handleOverloadedOperator(CheckerContext &C, const CallEvent &Call, OverloadedOperatorKind Op) const; @@ -100,9 +99,8 @@ class IteratorModeling const Expr *OrigExpr, const AdvanceFn *Handler) const; - void handleComparison(CheckerContext &C, const Expr *CE, - ConstCFGElementRef Elem, SVal RetVal, SVal LVal, - SVal RVal, OverloadedOperatorKind Op) const; + void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal, + SVal LVal, SVal RVal, OverloadedOperatorKind Op) const; void processComparison(CheckerContext &C, ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, SVal RetVal, OverloadedOperatorKind Op) const; @@ -110,20 +108,19 @@ class IteratorModeling bool Postfix) const; void handleDecrement(CheckerContext &C, SVal RetVal, SVal Iter, bool Postfix) const; - void handleRandomIncrOrDecr(CheckerContext &C, ConstCFGElementRef Elem, + void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, OverloadedOperatorKind Op, SVal RetVal, SVal Iterator, SVal Amount) const; void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, - ConstCFGElementRef Elem, OverloadedOperatorKind OK, - SVal Offset) const; - void handleAdvance(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, - SVal Iter, SVal Amount) const; - void handlePrev(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, - SVal Iter, SVal Amount) const; - void handleNext(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal, - SVal Iter, SVal Amount) const; - void assignToContainer(CheckerContext &C, ConstCFGElementRef Elem, - SVal RetVal, const MemRegion *Cont) const; + OverloadedOperatorKind OK, SVal Offset) const; + void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, + SVal Amount) const; + void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, + SVal Amount) const; + void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, + SVal Amount) const; + void assignToContainer(CheckerContext &C, const Expr *CE, SVal RetVal, + const MemRegion *Cont) const; bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; @@ -227,7 +224,7 @@ void IteratorModeling::checkPostCall(const CallEvent &Call, C.getASTContext()).getTypePtr() == Call.getResultType().getDesugaredType(C.getASTContext()).getTypePtr()) { if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) { - assignToContainer(C, Call.getCFGElementRef(), Call.getReturnValue(), + assignToContainer(C, OrigExpr, Call.getReturnValue(), Pos->getContainer()); return; } @@ -258,7 +255,7 @@ void IteratorModeling::checkPostStmt(const UnaryOperator *UO, return; auto &SVB = C.getSValBuilder(); - handlePtrIncrOrDecr(C, UO->getSubExpr(), C.getCFGElementRef(), + handlePtrIncrOrDecr(C, UO->getSubExpr(), isIncrementOperator(OK) ? OO_Plus : OO_Minus, SVB.makeArrayIndex(1)); } @@ -274,7 +271,7 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO, if (isSimpleComparisonOperator(BO->getOpcode())) { SVal Result = State->getSVal(BO, C.getLocationContext()); - handleComparison(C, BO, C.getCFGElementRef(), Result, LVal, RVal, + handleComparison(C, BO, Result, LVal, RVal, BinaryOperator::getOverloadedOperator(OK)); } else if (isRandomIncrOrDecrOperator(OK)) { // In case of operator+ the iterator can be either on the LHS (eg.: it + 1), @@ -287,8 +284,8 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO, if (!AmountExpr->getType()->isIntegralOrEnumerationType()) return; SVal AmountVal = IsIterOnLHS ? RVal : LVal; - handlePtrIncrOrDecr(C, IterExpr, C.getCFGElementRef(), - BinaryOperator::getOverloadedOperator(OK), AmountVal); + handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK), + AmountVal); } } @@ -354,29 +351,27 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C, OverloadedOperatorKind Op) const { if (isSimpleComparisonOperator(Op)) { const auto *OrigExpr = Call.getOriginExpr(); - const auto Elem = Call.getCFGElementRef(); if (!OrigExpr) return; if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - handleComparison(C, OrigExpr, Elem, Call.getReturnValue(), + handleComparison(C, OrigExpr, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); return; } - handleComparison(C, OrigExpr, Elem, Call.getReturnValue(), - Call.getArgSVal(0), Call.getArgSVal(1), Op); + handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), + Call.getArgSVal(1), Op); return; } else if (isRandomIncrOrDecrOperator(Op)) { const auto *OrigExpr = Call.getOriginExpr(); - const auto Elem = Call.getCFGElementRef(); if (!OrigExpr) return; if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { if (Call.getNumArgs() >= 1 && Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { - handleRandomIncrOrDecr(C, Elem, Op, Call.getReturnValue(), + handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0)); return; } @@ -396,8 +391,8 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C, SVal Iterator = IsIterFirst ? FirstArg : SecondArg; SVal Amount = IsIterFirst ? SecondArg : FirstArg; - handleRandomIncrOrDecr(C, Elem, Op, Call.getReturnValue(), Iterator, - Amount); + handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), + Iterator, Amount); return; } } @@ -430,7 +425,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, const Expr *OrigExpr, const AdvanceFn *Handler) const { if (!C.wasInlined) { - (this->**Handler)(C, Call.getCFGElementRef(), Call.getReturnValue(), + (this->**Handler)(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1)); return; } @@ -441,7 +436,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, if (IdInfo) { if (IdInfo->getName() == "advance") { if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) { - (this->**Handler)(C, Call.getCFGElementRef(), Call.getReturnValue(), + (this->**Handler)(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1)); } } @@ -449,8 +444,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C, } void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, - ConstCFGElementRef Elem, SVal RetVal, - SVal LVal, SVal RVal, + SVal RetVal, SVal LVal, SVal RVal, OverloadedOperatorKind Op) const { // Record the operands and the operator of the comparison for the next // evalAssume, if the result is a symbolic expression. If it is a concrete @@ -473,7 +467,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, SymbolRef Sym; if (!LPos || !RPos) { auto &SymMgr = C.getSymbolManager(); - Sym = SymMgr.conjureSymbol(Elem, C.getLocationContext(), + Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = assumeNoOverflow(State, Sym, 4); } @@ -500,7 +494,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, auto &SymMgr = C.getSymbolManager(); auto *LCtx = C.getLocationContext(); RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol( - Elem, LCtx, C.getASTContext().BoolTy, C.blockCount())); + CE, LCtx, C.getASTContext().BoolTy, C.blockCount())); State = State->BindExpr(CE, LCtx, RetVal); } @@ -589,8 +583,7 @@ void IteratorModeling::handleDecrement(CheckerContext &C, SVal RetVal, C.addTransition(State); } -void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, - ConstCFGElementRef Elem, +void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, OverloadedOperatorKind Op, SVal RetVal, SVal Iterator, SVal Amount) const { @@ -624,13 +617,12 @@ void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, State = setIteratorPosition(State, TgtVal, *NewPos); C.addTransition(State); } else { - assignToContainer(C, Elem, TgtVal, Pos->getContainer()); + assignToContainer(C, CE, TgtVal, Pos->getContainer()); } } void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, - ConstCFGElementRef Elem, OverloadedOperatorKind OK, SVal Offset) const { if (!isa<DefinedSVal>(Offset)) @@ -669,35 +661,34 @@ void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C, ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos); C.addTransition(NewState); } else { - assignToContainer(C, Elem, NewVal, OldPos->getContainer()); + assignToContainer(C, Iterator, NewVal, OldPos->getContainer()); } } -void IteratorModeling::handleAdvance(CheckerContext &C, ConstCFGElementRef Elem, +void IteratorModeling::handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, Elem, OO_PlusEqual, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, CE, OO_PlusEqual, RetVal, Iter, Amount); } -void IteratorModeling::handlePrev(CheckerContext &C, ConstCFGElementRef Elem, +void IteratorModeling::handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, Elem, OO_Minus, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, CE, OO_Minus, RetVal, Iter, Amount); } -void IteratorModeling::handleNext(CheckerContext &C, ConstCFGElementRef Elem, +void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, SVal Amount) const { - handleRandomIncrOrDecr(C, Elem, OO_Plus, RetVal, Iter, Amount); + handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount); } -void IteratorModeling::assignToContainer(CheckerContext &C, - ConstCFGElementRef Elem, SVal RetVal, +void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE, + SVal RetVal, const MemRegion *Cont) const { Cont = Cont->getMostDerivedObjectRegion(); auto State = C.getState(); const auto *LCtx = C.getLocationContext(); - State = - createIteratorPosition(State, RetVal, Cont, Elem, LCtx, C.blockCount()); + State = createIteratorPosition(State, RetVal, Cont, CE, LCtx, C.blockCount()); C.addTransition(State); } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index e970a89..1c4293c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1833,10 +1833,8 @@ ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C, unsigned Count = C.blockCount(); SValBuilder &SVB = C.getSValBuilder(); const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); - DefinedSVal RetVal = - isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count) - : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx, - CE->getType(), Count); + DefinedSVal RetVal = isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count) + : SVB.getConjuredHeapSymbolVal(CE, LCtx, Count); return State->BindExpr(CE, C.getLocationContext(), RetVal); } @@ -2306,7 +2304,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr, // Assume that after memory is freed, it contains unknown values. This // conforts languages standards, since reading from freed memory is considered // UB and may result in arbitrary value. - State = State->invalidateRegions({location}, Call.getCFGElementRef(), + State = State->invalidateRegions({location}, Call.getOriginExpr(), C.blockCount(), C.getLocationContext(), /*CausesPointerEscape=*/false, /*InvalidatedSymbols=*/nullptr); diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 03a6b60..cc1ced7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -932,8 +932,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call, (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { SValBuilder &SVB = C.getSValBuilder(); RetVal = - SVB.conjureSymbolVal(/*symbolTag=*/nullptr, Call.getCFGElementRef(), - LCtx, ResultTy, C.blockCount()); + SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); } // Bind the value. diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp index 8e19963..e037719 100644 --- a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp @@ -25,12 +25,12 @@ using namespace iterator; namespace { class STLAlgorithmModeling : public Checker<eval::Call> { - bool evalFind(CheckerContext &C, const CallEvent &Call) const; + bool evalFind(CheckerContext &C, const CallExpr *CE) const; - void Find(CheckerContext &C, const CallEvent &Call, unsigned paramNum) const; + void Find(CheckerContext &C, const CallExpr *CE, unsigned paramNum) const; using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &, - const CallEvent &Call) const; + const CallExpr *) const; const CallDescriptionMap<FnCheck> Callbacks = { {{CDM::SimpleFunc, {"std", "find"}, 3}, &STLAlgorithmModeling::evalFind}, @@ -97,12 +97,11 @@ bool STLAlgorithmModeling::evalCall(const CallEvent &Call, if (!Handler) return false; - return (this->**Handler)(C, Call); + return (this->**Handler)(C, CE); } bool STLAlgorithmModeling::evalFind(CheckerContext &C, - const CallEvent &Call) const { - const auto *CE = dyn_cast<CallExpr>(Call.getOriginExpr()); + const CallExpr *CE) const { // std::find()-like functions either take their primary range in the first // two parameters, or if the first parameter is "execution policy" then in // the second and third. This means that the second parameter must always be @@ -113,29 +112,27 @@ bool STLAlgorithmModeling::evalFind(CheckerContext &C, // If no "execution policy" parameter is used then the first argument is the // beginning of the range. if (isIteratorType(CE->getArg(0)->getType())) { - Find(C, Call, 0); + Find(C, CE, 0); return true; } // If "execution policy" parameter is used then the second argument is the // beginning of the range. if (isIteratorType(CE->getArg(2)->getType())) { - Find(C, Call, 1); + Find(C, CE, 1); return true; } return false; } -void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call, +void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE, unsigned paramNum) const { - const auto *CE = dyn_cast<CallExpr>(Call.getOriginExpr()); - const auto &Elem = Call.getCFGElementRef(); auto State = C.getState(); auto &SVB = C.getSValBuilder(); const auto *LCtx = C.getLocationContext(); - SVal RetVal = SVB.conjureSymbolVal(nullptr, Elem, LCtx, C.blockCount()); + SVal RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); SVal Param = State->getSVal(CE->getArg(paramNum), LCtx); auto StateFound = State->BindExpr(CE, LCtx, RetVal); @@ -147,7 +144,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call, const auto *Pos = getIteratorPosition(State, Param); if (Pos) { StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(), - Elem, LCtx, C.blockCount()); + CE, LCtx, C.blockCount()); const auto *NewPos = getIteratorPosition(StateFound, RetVal); assert(NewPos && "Failed to create new iterator position."); @@ -169,7 +166,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call, Pos = getIteratorPosition(State, Param); if (Pos) { StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(), - Elem, LCtx, C.blockCount()); + CE, LCtx, C.blockCount()); const auto *NewPos = getIteratorPosition(StateFound, RetVal); assert(NewPos && "Failed to create new iterator position."); @@ -202,3 +199,4 @@ void ento::registerSTLAlgorithmModeling(CheckerManager &Mgr) { bool ento::shouldRegisterSTLAlgorithmModeling(const CheckerManager &mgr) { return true; } + diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp index 9b0ce15..321388a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -78,9 +78,10 @@ private: bool handleOstreamOperator(const CallEvent &Call, CheckerContext &C) const; bool handleSwap(ProgramStateRef State, SVal First, SVal Second, CheckerContext &C) const; - std::pair<SVal, ProgramStateRef> retrieveOrConjureInnerPtrVal( - ProgramStateRef State, const MemRegion *ThisRegion, - ConstCFGElementRef Elem, QualType Type, CheckerContext &C) const; + std::pair<SVal, ProgramStateRef> + retrieveOrConjureInnerPtrVal(ProgramStateRef State, + const MemRegion *ThisRegion, const Expr *E, + QualType Type, CheckerContext &C) const; using SmartPtrMethodHandlerFn = void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const; @@ -305,7 +306,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, return false; const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal( - Call.getCFGElementRef(), C.getLocationContext(), + Call.getOriginExpr(), C.getLocationContext(), getPointerTypeFromTemplateArg(Call, C), C.blockCount()); const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion(); @@ -436,12 +437,12 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, } std::pair<SVal, ProgramStateRef> SmartPtrModeling::retrieveOrConjureInnerPtrVal( - ProgramStateRef State, const MemRegion *ThisRegion, ConstCFGElementRef Elem, + ProgramStateRef State, const MemRegion *ThisRegion, const Expr *E, QualType Type, CheckerContext &C) const { const auto *Ptr = State->get<TrackedRegionMap>(ThisRegion); if (Ptr) return {*Ptr, State}; - auto Val = C.getSValBuilder().conjureSymbolVal(Elem, C.getLocationContext(), + auto Val = C.getSValBuilder().conjureSymbolVal(E, C.getLocationContext(), Type, C.blockCount()); State = State->set<TrackedRegionMap>(ThisRegion, Val); return {Val, State}; @@ -468,7 +469,6 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call, // https://en.cppreference.com/w/cpp/memory/unique_ptr/operator_cmp. auto makeSValFor = [&C, this](ProgramStateRef State, const Expr *E, - ConstCFGElementRef Elem, SVal S) -> std::pair<SVal, ProgramStateRef> { if (S.isZeroConstant()) { return {S, State}; @@ -477,7 +477,7 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call, assert(Reg && "this pointer of std::unique_ptr should be obtainable as MemRegion"); QualType Type = getInnerPointerType(C, E->getType()->getAsCXXRecordDecl()); - return retrieveOrConjureInnerPtrVal(State, Reg, Elem, Type, C); + return retrieveOrConjureInnerPtrVal(State, Reg, E, Type, C); }; SVal First = Call.getArgSVal(0); @@ -491,10 +491,8 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call, ProgramStateRef State = C.getState(); SVal FirstPtrVal, SecondPtrVal; - std::tie(FirstPtrVal, State) = - makeSValFor(State, FirstExpr, Call.getCFGElementRef(), First); - std::tie(SecondPtrVal, State) = - makeSValFor(State, SecondExpr, Call.getCFGElementRef(), Second); + std::tie(FirstPtrVal, State) = makeSValFor(State, FirstExpr, First); + std::tie(SecondPtrVal, State) = makeSValFor(State, SecondExpr, Second); BinaryOperatorKind BOK = operationKindFromOverloadedOperator(OOK, true).GetBinaryOpUnsafe(); auto RetVal = Bldr.evalBinOp(State, BOK, FirstPtrVal, SecondPtrVal, @@ -532,7 +530,7 @@ bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call, if (!StreamThisRegion) return false; State = - State->invalidateRegions({StreamThisRegion}, Call.getCFGElementRef(), + State->invalidateRegions({StreamThisRegion}, Call.getOriginExpr(), C.blockCount(), C.getLocationContext(), false); State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal); @@ -724,7 +722,7 @@ void SmartPtrModeling::handleGet(const CallEvent &Call, SVal InnerPointerVal; std::tie(InnerPointerVal, State) = retrieveOrConjureInnerPtrVal( - State, ThisRegion, Call.getCFGElementRef(), Call.getResultType(), C); + State, ThisRegion, Call.getOriginExpr(), Call.getResultType(), C); State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), InnerPointerVal); // TODO: Add NoteTag, for how the raw pointer got using 'get' method. @@ -855,7 +853,7 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call, const LocationContext *LC = C.getLocationContext(); InnerPointerVal = C.getSValBuilder().conjureSymbolVal( - Call.getCFGElementRef(), LC, InnerPointerType, C.blockCount()); + CallExpr, LC, InnerPointerType, C.blockCount()); State = State->set<TrackedRegionMap>(ThisRegion, InnerPointerVal); } diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 3628a14..9c0b79a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -585,7 +585,7 @@ class StdLibraryFunctionsChecker CheckerContext &C) const override { SValBuilder &SVB = C.getSValBuilder(); NonLoc ErrnoSVal = - SVB.conjureSymbolVal(&Tag, Call.getCFGElementRef(), + SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(), C.getLocationContext(), C.getASTContext().IntTy, C.blockCount()) .castAs<NonLoc>(); @@ -621,7 +621,7 @@ class StdLibraryFunctionsChecker const Summary &Summary, CheckerContext &C) const override { return errno_modeling::setErrnoStdMustBeChecked(State, C, - Call.getCFGElementRef()); + Call.getOriginExpr()); } const std::string describe(CheckerContext &C) const override { @@ -1482,8 +1482,7 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call, const LocationContext *LC = C.getLocationContext(); const auto *CE = cast<CallExpr>(Call.getOriginExpr()); SVal V = C.getSValBuilder().conjureSymbolVal( - Call.getCFGElementRef(), LC, CE->getType().getCanonicalType(), - C.blockCount()); + CE, LC, CE->getType().getCanonicalType(), C.blockCount()); State = State->BindExpr(CE, LC, V); C.addTransition(State); diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 6481b76..80969ce 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -224,16 +224,18 @@ SVal getStreamArg(const FnDescription *Desc, const CallEvent &Call) { } /// Create a conjured symbol return value for a call expression. -DefinedSVal makeRetVal(CheckerContext &C, ConstCFGElementRef Elem) { +DefinedSVal makeRetVal(CheckerContext &C, const CallExpr *CE) { + assert(CE && "Expecting a call expression."); + + const LocationContext *LCtx = C.getLocationContext(); return C.getSValBuilder() - .conjureSymbolVal(/*symbolTag=*/nullptr, Elem, C.getLocationContext(), - C.blockCount()) + .conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()) .castAs<DefinedSVal>(); } ProgramStateRef bindAndAssumeTrue(ProgramStateRef State, CheckerContext &C, - const CallExpr *CE, ConstCFGElementRef Elem) { - DefinedSVal RetVal = makeRetVal(C, Elem); + const CallExpr *CE) { + DefinedSVal RetVal = makeRetVal(C, CE); State = State->BindExpr(CE, C.getLocationContext(), RetVal); State = State->assume(RetVal, true); assert(State && "Assumption on new value should not fail."); @@ -643,7 +645,6 @@ struct StreamOperationEvaluator { SymbolRef StreamSym = nullptr; const StreamState *SS = nullptr; const CallExpr *CE = nullptr; - std::optional<ConstCFGElementRef> Elem; StreamErrorState NewES; StreamOperationEvaluator(CheckerContext &C) @@ -663,7 +664,6 @@ struct StreamOperationEvaluator { CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); if (!CE) return false; - Elem = Call.getCFGElementRef(); assertStreamStateOpened(SS); @@ -683,7 +683,7 @@ struct StreamOperationEvaluator { } ProgramStateRef makeAndBindRetVal(ProgramStateRef State, CheckerContext &C) { - NonLoc RetVal = makeRetVal(C, Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>(); return State->BindExpr(CE, C.getLocationContext(), RetVal); } @@ -716,7 +716,7 @@ struct StreamOperationEvaluator { ConstraintManager::ProgramStatePair makeRetValAndAssumeDual(ProgramStateRef State, CheckerContext &C) { - DefinedSVal RetVal = makeRetVal(C, Elem.value()); + DefinedSVal RetVal = makeRetVal(C, CE); State = State->BindExpr(CE, C.getLocationContext(), RetVal); return C.getConstraintManager().assumeDual(State, RetVal); } @@ -858,7 +858,7 @@ escapeByStartIndexAndCount(ProgramStateRef State, const CallEvent &Call, ITraits.setTrait(Element, DoNotInvalidateSuperRegion); } return State->invalidateRegions( - EscapingVals, Call.getCFGElementRef(), BlockCount, LCtx, + EscapingVals, Call.getOriginExpr(), BlockCount, LCtx, /*CausesPointerEscape=*/false, /*InvalidatedSymbols=*/nullptr, &Call, &ITraits); } @@ -868,7 +868,7 @@ static ProgramStateRef escapeArgs(ProgramStateRef State, CheckerContext &C, ArrayRef<unsigned int> EscapingArgs) { auto GetArgSVal = [&Call](int Idx) { return Call.getArgSVal(Idx); }; auto EscapingVals = to_vector(map_range(EscapingArgs, GetArgSVal)); - State = State->invalidateRegions(EscapingVals, Call.getCFGElementRef(), + State = State->invalidateRegions(EscapingVals, Call.getOriginExpr(), C.blockCount(), C.getLocationContext(), /*CausesPointerEscape=*/false, /*InvalidatedSymbols=*/nullptr); @@ -931,7 +931,7 @@ void StreamChecker::evalFopen(const FnDescription *Desc, const CallEvent &Call, if (!CE) return; - DefinedSVal RetVal = makeRetVal(C, Call.getCFGElementRef()); + DefinedSVal RetVal = makeRetVal(C, CE); SymbolRef RetSym = RetVal.getAsSymbol(); assert(RetSym && "RetVal must be a symbol here."); @@ -1200,7 +1200,7 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc, if (!IsFread && !PedanticMode) return; - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>(); ProgramStateRef StateFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateFailed = E.assumeBinOpNN(StateFailed, BO_LT, RetVal, *NMembVal); @@ -1235,7 +1235,7 @@ void StreamChecker::evalFgetx(const FnDescription *Desc, const CallEvent &Call, State = escapeArgs(State, C, Call, {0}); if (SingleChar) { // Generate a transition for the success state of `fgetc`. - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); // The returned 'unsigned char' of `fgetc` is converted to 'int', @@ -1300,7 +1300,7 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call, C.addTransition(StateNotFailed); } else { // Generate a transition for the success state of `fputs`. - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateNotFailed = @@ -1334,7 +1334,7 @@ void StreamChecker::evalFprintf(const FnDescription *Desc, if (!E.Init(Desc, Call, C, State)) return; - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>(); State = State->BindExpr(E.CE, C.getLocationContext(), RetVal); auto Cond = E.SVB @@ -1379,7 +1379,7 @@ void StreamChecker::evalFscanf(const FnDescription *Desc, const CallEvent &Call, // case, and no error flags are set on the stream. This is probably not // accurate, and the POSIX documentation does not tell more. if (!E.isStreamEof()) { - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateNotFailed = @@ -1460,7 +1460,7 @@ void StreamChecker::evalGetdelim(const FnDescription *Desc, State = escapeArgs(State, C, Call, {0, 1}); // Add transition for the successful state. - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>(); ProgramStateRef StateNotFailed = E.bindReturnValue(State, C, RetVal); StateNotFailed = E.assumeBinOpNN(StateNotFailed, BO_GE, RetVal, E.getZeroVal(Call)); @@ -1601,7 +1601,7 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call, if (!E.Init(Desc, Call, C, State)) return; - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>(); ProgramStateRef StateNotFailed = State->BindExpr(E.CE, C.getLocationContext(), RetVal); StateNotFailed = @@ -1735,8 +1735,7 @@ void StreamChecker::evalFeofFerror(const FnDescription *Desc, // Execution path with error of ErrorKind. // Function returns true. // From now on it is the only one error state. - ProgramStateRef TrueState = - bindAndAssumeTrue(State, C, E.CE, E.Elem.value()); + ProgramStateRef TrueState = bindAndAssumeTrue(State, C, E.CE); C.addTransition(E.setStreamState( TrueState, StreamState::getOpened(Desc, ErrorKind, E.SS->FilePositionIndeterminate && @@ -1770,7 +1769,7 @@ void StreamChecker::evalFileno(const FnDescription *Desc, const CallEvent &Call, if (!E.Init(Desc, Call, C, State)) return; - NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>(); + NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>(); State = State->BindExpr(E.CE, C.getLocationContext(), RetVal); State = E.assumeBinOpNN(State, BO_GE, RetVal, E.getZeroVal(Call)); if (!State) diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp index 044f9ba..fefe846 100644 --- a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp @@ -207,7 +207,7 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall( // Function call will return a pointer to the new symbolic region. DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal( - Call.getCFGElementRef(), LCtx, CE->getType(), C.blockCount()); + CE, LCtx, CE->getType(), C.blockCount()); State = State->BindExpr(CE, LCtx, RetVal); const auto *SymRegOfRetVal = diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 583315f..bb4a39f 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -280,7 +280,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, // Invalidate designated regions using the batch invalidation API. // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate // global variables. - return Result->invalidateRegions(ValuesToInvalidate, getCFGElementRef(), + return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), BlockCount, getLocationContext(), /*CausedByPointerEscape*/ true, /*Symbols=*/nullptr, this, &ETraits); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 2af6a60..86e2e8f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -422,7 +422,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( break; case SubobjectAdjustment::MemberPointerAdjustment: // FIXME: Unimplemented. - State = State->invalidateRegions(Reg, getCFGElementRef(), + State = State->invalidateRegions(Reg, InitWithAdjustments, currBldrCtx->blockCount(), LC, true, nullptr, nullptr, nullptr); return State; @@ -439,8 +439,8 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( // values inside Reg would be correct. SVal InitVal = State->getSVal(Init, LC); if (InitVal.isUnknown()) { - InitVal = getSValBuilder().conjureSymbolVal( - getCFGElementRef(), LC, Init->getType(), currBldrCtx->blockCount()); + InitVal = getSValBuilder().conjureSymbolVal(Result, LC, Init->getType(), + currBldrCtx->blockCount()); State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false); // Then we'd need to take the value that certainly exists and bind it @@ -449,7 +449,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( // Try to recover some path sensitivity in case we couldn't // compute the value. InitValWithAdjustments = getSValBuilder().conjureSymbolVal( - getCFGElementRef(), LC, InitWithAdjustments->getType(), + Result, LC, InitWithAdjustments->getType(), currBldrCtx->blockCount()); } State = @@ -1215,9 +1215,9 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit, // If we fail to get the value for some reason, use a symbolic value. if (InitVal.isUnknownOrUndef()) { SValBuilder &SVB = getSValBuilder(); - InitVal = - SVB.conjureSymbolVal(getCFGElementRef(), stackFrame, - Field->getType(), currBldrCtx->blockCount()); + InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame, + Field->getType(), + currBldrCtx->blockCount()); } } else { InitVal = State->getSVal(BMI->getInit(), stackFrame); @@ -2051,9 +2051,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, for (const auto N : preVisit) { const LocationContext *LCtx = N->getLocationContext(); - SVal result = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, - currBldrCtx->blockCount()); + SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, + resultType, + currBldrCtx->blockCount()); ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result); // Escape pointers passed into the list, unless it's an ObjC boxed @@ -2556,18 +2556,10 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt(); if (!isa_and_nonnull<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(Term)) return; - // Widen. const LocationContext *LCtx = Pred->getLocationContext(); - - // FIXME: - // We cannot use the CFG element from the via `ExprEngine::getCFGElementRef` - // since we are currently at the block entrance and the current reference - // would be stale. Ideally, we should pass on the terminator of the CFG - // block, but the terminator cannot be referred as a CFG element. - // Here we just pass the current stale block. - ProgramStateRef WidenedState = getWidenedLoopState( - Pred->getState(), LCtx, BlockCount, getCFGElementRef()); + ProgramStateRef WidenedState = + getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term); nodeBuilder.generateNode(WidenedState, Pred); return; } @@ -3549,10 +3541,11 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, ValuesToInvalidate.push_back(SubExprVal); } - State = State->invalidateRegions(ValuesToInvalidate, getCFGElementRef(), - currBldrCtx->blockCount(), LCtx, - /*CausedByPointerEscape*/ true, - /*Symbols=*/nullptr); + State = State->invalidateRegions(ValuesToInvalidate, AE, + currBldrCtx->blockCount(), + LCtx, + /*CausedByPointerEscape*/true, + /*Symbols=*/nullptr); SVal ResultVal = UnknownVal(); State = State->BindExpr(AE, LCtx, ResultVal); @@ -3899,8 +3892,7 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, assert(!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef. if (std::optional<Loc> LV = X.getAs<Loc>()) - state = state->invalidateRegions(*LV, getCFGElementRef(), - currBldrCtx->blockCount(), + state = state->invalidateRegions(*LV, A, currBldrCtx->blockCount(), Pred->getLocationContext(), /*CausedByPointerEscape=*/true); } @@ -3910,8 +3902,7 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, SVal X = state->getSVal(I, Pred->getLocationContext()); if (std::optional<Loc> LV = X.getAs<Loc>()) - state = state->invalidateRegions(*LV, getCFGElementRef(), - currBldrCtx->blockCount(), + state = state->invalidateRegions(*LV, A, currBldrCtx->blockCount(), Pred->getLocationContext(), /*CausedByPointerEscape=*/true); } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 6e52df5..3d0a69a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -21,19 +21,18 @@ using namespace ento; using llvm::APSInt; /// Optionally conjure and return a symbol for offset when processing -/// \p Elem. +/// an expression \p Expression. /// If \p Other is a location, conjure a symbol for \p Symbol /// (offset) if it is unknown so that memory arithmetic always /// results in an ElementRegion. /// \p Count The number of times the current basic block was visited. -static SVal conjureOffsetSymbolOnLocation(SVal Symbol, SVal Other, - ConstCFGElementRef Elem, QualType Ty, - SValBuilder &svalBuilder, - unsigned Count, - const LocationContext *LCtx) { +static SVal conjureOffsetSymbolOnLocation( + SVal Symbol, SVal Other, Expr* Expression, SValBuilder &svalBuilder, + unsigned Count, const LocationContext *LCtx) { + QualType Ty = Expression->getType(); if (isa<Loc>(Other) && Ty->isIntegralOrEnumerationType() && Symbol.isUnknown()) { - return svalBuilder.conjureSymbolVal(Elem, LCtx, Ty, Count); + return svalBuilder.conjureSymbolVal(Expression, LCtx, Ty, Count); } return Symbol; } @@ -66,7 +65,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // FIXME: Handle structs. if (RightV.isUnknown()) { unsigned Count = currBldrCtx->blockCount(); - RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx, + RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, Count); } // Simulate the effects of a "store": bind the value of the RHS @@ -85,11 +84,9 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // SymSymExpr. unsigned Count = currBldrCtx->blockCount(); RightV = conjureOffsetSymbolOnLocation( - RightV, LeftV, getCFGElementRef(), RHS->getType(), svalBuilder, - Count, LCtx); - LeftV = conjureOffsetSymbolOnLocation(LeftV, RightV, getCFGElementRef(), - LHS->getType(), svalBuilder, - Count, LCtx); + RightV, LeftV, RHS, svalBuilder, Count, LCtx); + LeftV = conjureOffsetSymbolOnLocation( + LeftV, RightV, LHS, svalBuilder, Count, LCtx); } // Although we don't yet model pointers-to-members, we do need to make @@ -168,8 +165,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // The symbolic value is actually for the type of the left-hand side // expression, not the computation type, as this is the value the // LValue on the LHS will bind to. - LHSVal = svalBuilder.conjureSymbolVal(/*symbolTag=*/nullptr, - getCFGElementRef(), LCtx, LTy, + LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy, currBldrCtx->blockCount()); // However, we need to convert the symbol to the computation type. Result = svalBuilder.evalCast(LHSVal, CTy, LTy); @@ -463,9 +459,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, } else { // If we don't know if the cast succeeded, conjure a new symbol. if (val.isUnknown()) { - DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, - currBldrCtx->blockCount()); + DefinedOrUnknownSVal NewSym = + svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, + currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, NewSym); } else // Else, bind to the derived region value. @@ -487,9 +483,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, // Failed to cast or the result is unknown, fall back to conservative. if (val.isUnknown()) { - val = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, - currBldrCtx->blockCount()); + val = + svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, + currBldrCtx->blockCount()); } state = state->BindExpr(CastE, LCtx, val); Bldr.generateNode(CastE, Pred, state); @@ -533,7 +529,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); SVal result = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType, + /*symbolTag=*/nullptr, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); @@ -625,9 +621,8 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Ty = getContext().getPointerType(Ty); } - InitVal = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LC, Ty, - currBldrCtx->blockCount()); + InitVal = svalBuilder.conjureSymbolVal(nullptr, InitEx, LC, Ty, + currBldrCtx->blockCount()); } @@ -844,7 +839,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, } if (!hasValue) - V = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx, + V = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, currBldrCtx->blockCount()); // Generate a new node with the binding from the appropriate path. @@ -1126,9 +1121,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, // Conjure a new symbol if necessary to recover precision. if (Result.isUnknown()){ - DefinedOrUnknownSVal SymVal = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, - currBldrCtx->blockCount()); + DefinedOrUnknownSVal SymVal = + svalBuilder.conjureSymbolVal(nullptr, U, LCtx, + currBldrCtx->blockCount()); Result = SymVal; // If the value is a location, ++/-- should always preserve diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 5804dc1..92ce3fa 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -242,8 +242,8 @@ SVal ExprEngine::computeObjectUnderConstruction( assert(RetE && "Void returns should not have a construction context"); QualType ReturnTy = RetE->getType(); QualType RegionTy = ACtx.getPointerType(ReturnTy); - return SVB.conjureSymbolVal(&TopLevelSymRegionTag, getCFGElementRef(), - SFC, RegionTy, currBldrCtx->blockCount()); + return SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, RegionTy, + currBldrCtx->blockCount()); } llvm_unreachable("Unhandled return value construction context!"); } @@ -975,11 +975,10 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // a custom global allocator. if (symVal.isUnknown()) { if (IsStandardGlobalOpNewFunction) - symVal = svalBuilder.getConjuredHeapSymbolVal(getCFGElementRef(), LCtx, - CNE->getType(), blockCount); + symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); else - symVal = svalBuilder.conjureSymbolVal( - /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, blockCount); + symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), + blockCount); } CallEventManager &CEMgr = getStateManager().getCallEventManager(); @@ -1112,7 +1111,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, } const LocationContext *LCtx = Pred->getLocationContext(); - SVal V = svalBuilder.conjureSymbolVal(getCFGElementRef(), LCtx, VD->getType(), + SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(), currBldrCtx->blockCount()); ProgramStateRef state = Pred->getState(); state = state->bindLoc(state->getLValue(VD, LCtx), V, LCtx); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 90625a9..1a44ba4 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -746,7 +746,6 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, const LocationContext *LCtx, ProgramStateRef State) { const Expr *E = Call.getOriginExpr(); - const ConstCFGElementRef &Elem = Call.getCFGElementRef(); if (!E) return State; @@ -789,7 +788,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, RegionAndSymbolInvalidationTraits ITraits; ITraits.setTrait(TargetR, RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); - State = State->invalidateRegions(TargetR, Elem, Count, LCtx, + State = State->invalidateRegions(TargetR, E, Count, LCtx, /* CausesPointerEscape=*/false, nullptr, &Call, &ITraits); @@ -801,7 +800,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, // a regular unknown pointer. const auto *CNE = dyn_cast<CXXNewExpr>(E); if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) { - R = svalBuilder.getConjuredHeapSymbolVal(Elem, LCtx, E->getType(), Count); + R = svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count); const MemRegion *MR = R.getAsRegion()->StripCasts(); // Store the extent of the allocated object(s). @@ -825,7 +824,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, State = setDynamicExtent(State, MR, Size.castAs<DefinedOrUnknownSVal>()); } else { - R = svalBuilder.conjureSymbolVal(Elem, LCtx, ResultTy, Count); + R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count); } } return State->BindExpr(E, LCtx, R); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index f2e5a16..9426e0a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -45,7 +45,7 @@ void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, /// for-loop iterator. static void populateObjCForDestinationSet( ExplodedNodeSet &dstLocation, SValBuilder &svalBuilder, - const ObjCForCollectionStmt *S, ConstCFGElementRef elem, SVal elementV, + const ObjCForCollectionStmt *S, const Stmt *elem, SVal elementV, SymbolManager &SymMgr, const NodeBuilderContext *currBldrCtx, StmtNodeBuilder &Bldr, bool hasElements) { @@ -66,8 +66,8 @@ static void populateObjCForDestinationSet( SVal V; if (hasElements) { - SymbolRef Sym = - SymMgr.conjureSymbol(elem, LCtx, T, currBldrCtx->blockCount()); + SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T, + currBldrCtx->blockCount()); V = svalBuilder.makeLoc(Sym); } else { V = svalBuilder.makeIntVal(0, T); @@ -110,7 +110,6 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, const Stmt *elem = S->getElement(); const Stmt *collection = S->getCollection(); - const ConstCFGElementRef &elemRef = getCFGElementRef(); ProgramStateRef state = Pred->getState(); SVal collectionV = state->getSVal(collection, Pred->getLocationContext()); @@ -133,12 +132,11 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, StmtNodeBuilder Bldr(dstLocation, Tmp, *currBldrCtx); if (!isContainerNull) - populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, - elemRef, elementV, SymMgr, currBldrCtx, - Bldr, + populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elem, + elementV, SymMgr, currBldrCtx, Bldr, /*hasElements=*/true); - populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elemRef, + populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elem, elementV, SymMgr, currBldrCtx, Bldr, /*hasElements=*/false); diff --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp index 2cddf1f..9e42801 100644 --- a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp +++ b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp @@ -13,10 +13,10 @@ /// //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" #include "clang/AST/AST.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" using namespace clang; using namespace ento; @@ -24,13 +24,31 @@ using namespace clang::ast_matchers; const auto MatchRef = "matchref"; +/// Return the loops condition Stmt or NULL if LoopStmt is not a loop +static const Expr *getLoopCondition(const Stmt *LoopStmt) { + switch (LoopStmt->getStmtClass()) { + default: + return nullptr; + case Stmt::ForStmtClass: + return cast<ForStmt>(LoopStmt)->getCond(); + case Stmt::WhileStmtClass: + return cast<WhileStmt>(LoopStmt)->getCond(); + case Stmt::DoStmtClass: + return cast<DoStmt>(LoopStmt)->getCond(); + case Stmt::CXXForRangeStmtClass: + return cast<CXXForRangeStmt>(LoopStmt)->getCond(); + } +} + namespace clang { namespace ento { ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, const LocationContext *LCtx, - unsigned BlockCount, - ConstCFGElementRef Elem) { + unsigned BlockCount, const Stmt *LoopStmt) { + + assert((isa<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(LoopStmt))); + // Invalidate values in the current state. // TODO Make this more conservative by only invalidating values that might // be modified by the body of the loop. @@ -75,8 +93,9 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, RegionAndSymbolInvalidationTraits::TK_PreserveContents); } - return PrevState->invalidateRegions(Regions, Elem, BlockCount, LCtx, true, - nullptr, nullptr, &ITraits); + return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt), + BlockCount, LCtx, true, nullptr, nullptr, + &ITraits); } } // end namespace ento diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 19af899..492209d 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -149,7 +149,7 @@ typedef ArrayRef<const MemRegion *> RegionList; typedef ArrayRef<SVal> ValueList; ProgramStateRef ProgramState::invalidateRegions( - RegionList Regions, ConstCFGElementRef Elem, unsigned Count, + RegionList Regions, const Stmt *S, unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape, InvalidatedSymbols *IS, const CallEvent *Call, RegionAndSymbolInvalidationTraits *ITraits) const { @@ -157,12 +157,12 @@ ProgramStateRef ProgramState::invalidateRegions( for (const MemRegion *Reg : Regions) Values.push_back(loc::MemRegionVal(Reg)); - return invalidateRegions(Values, Elem, Count, LCtx, CausedByPointerEscape, IS, + return invalidateRegions(Values, S, Count, LCtx, CausedByPointerEscape, IS, Call, ITraits); } ProgramStateRef ProgramState::invalidateRegions( - ValueList Values, ConstCFGElementRef Elem, unsigned Count, + ValueList Values, const Stmt *S, unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape, InvalidatedSymbols *IS, const CallEvent *Call, RegionAndSymbolInvalidationTraits *ITraits) const { @@ -181,7 +181,7 @@ ProgramStateRef ProgramState::invalidateRegions( StoreManager::InvalidatedRegions TopLevelInvalidated; StoreManager::InvalidatedRegions Invalidated; const StoreRef &NewStore = Mgr.StoreMgr->invalidateRegions( - getStore(), Values, Elem, Count, LCtx, Call, *IS, *ITraits, + getStore(), Values, S, Count, LCtx, Call, *IS, *ITraits, &TopLevelInvalidated, &Invalidated); ProgramStateRef NewState = makeWithStore(NewStore); diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index b692837..1cc9cb8 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -563,15 +563,15 @@ public: //===-------------------------------------------------------------------===// // Binding values to regions. //===-------------------------------------------------------------------===// - RegionBindingsRef - invalidateGlobalRegion(MemRegion::Kind K, ConstCFGElementRef Elem, - unsigned Count, const LocationContext *LCtx, - RegionBindingsRef B, InvalidatedRegions *Invalidated); - - StoreRef invalidateRegions(Store store, ArrayRef<SVal> Values, - ConstCFGElementRef Elem, unsigned Count, - const LocationContext *LCtx, const CallEvent *Call, - InvalidatedSymbols &IS, + RegionBindingsRef invalidateGlobalRegion(MemRegion::Kind K, const Stmt *S, + unsigned Count, + const LocationContext *LCtx, + RegionBindingsRef B, + InvalidatedRegions *Invalidated); + + StoreRef invalidateRegions(Store store, ArrayRef<SVal> Values, const Stmt *S, + unsigned Count, const LocationContext *LCtx, + const CallEvent *Call, InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *Invalidated, InvalidatedRegions *InvalidatedTopLevel) override; @@ -1147,7 +1147,7 @@ RegionStoreManager::removeSubRegionBindings(LimitedRegionBindingsConstRef B, namespace { class InvalidateRegionsWorker : public ClusterAnalysis<InvalidateRegionsWorker> { - ConstCFGElementRef Elem; + const Stmt *S; unsigned Count; const LocationContext *LCtx; InvalidatedSymbols &IS; @@ -1156,13 +1156,12 @@ class InvalidateRegionsWorker : public ClusterAnalysis<InvalidateRegionsWorker> GlobalsFilterKind GlobalsFilter; public: InvalidateRegionsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr, - RegionBindingsRef b, ConstCFGElementRef elem, - unsigned count, const LocationContext *lctx, - InvalidatedSymbols &is, + RegionBindingsRef b, const Stmt *S, unsigned count, + const LocationContext *lctx, InvalidatedSymbols &is, RegionAndSymbolInvalidationTraits &ITraitsIn, StoreManager::InvalidatedRegions *r, GlobalsFilterKind GFK) - : ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b), Elem(elem), + : ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b), S(S), Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn), Regions(r), GlobalsFilter(GFK) {} @@ -1297,7 +1296,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelevant. DefinedOrUnknownSVal V = - svalBuilder.conjureSymbolVal(baseR, Elem, LCtx, Ctx.IntTy, Count); + svalBuilder.conjureSymbolVal(baseR, S, LCtx, Ctx.IntTy, Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } @@ -1319,7 +1318,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelevant. DefinedOrUnknownSVal V = - svalBuilder.conjureSymbolVal(baseR, Elem, LCtx, Ctx.IntTy, Count); + svalBuilder.conjureSymbolVal(baseR, S, LCtx, Ctx.IntTy, Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } @@ -1387,13 +1386,13 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, conjure_default: // Set the default value of the array to conjured symbol. DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal( - baseR, Elem, LCtx, AT->getElementType(), Count); + baseR, S, LCtx, AT->getElementType(), Count); B = B.addBinding(baseR, BindingKey::Default, V); return; } DefinedOrUnknownSVal V = - svalBuilder.conjureSymbolVal(baseR, Elem, LCtx, T, Count); + svalBuilder.conjureSymbolVal(baseR, S, LCtx, T, Count); assert(SymbolManager::canSymbolicate(T) || V.isUnknown()); B = B.addBinding(baseR, BindingKey::Direct, V); } @@ -1422,15 +1421,15 @@ bool InvalidateRegionsWorker::includeEntireMemorySpace(const MemRegion *Base) { } RegionBindingsRef RegionStoreManager::invalidateGlobalRegion( - MemRegion::Kind K, ConstCFGElementRef Elem, unsigned Count, + MemRegion::Kind K, const Stmt *S, unsigned Count, const LocationContext *LCtx, RegionBindingsRef B, InvalidatedRegions *Invalidated) { // Bind the globals memory space to a new symbol that we will use to derive // the bindings for all globals. const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K); - SVal V = svalBuilder.conjureSymbolVal( - /* symbolTag = */ (const void *)GS, Elem, LCtx, - /* type does not matter */ Ctx.IntTy, Count); + SVal V = + svalBuilder.conjureSymbolVal(/* symbolTag = */ (const void *)GS, S, LCtx, + /* type does not matter */ Ctx.IntTy, Count); B = B.removeBinding(GS) .addBinding(BindingKey::Make(GS, BindingKey::Default), V); @@ -1465,7 +1464,7 @@ void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W, } StoreRef RegionStoreManager::invalidateRegions( - Store store, ArrayRef<SVal> Values, ConstCFGElementRef Elem, unsigned Count, + Store store, ArrayRef<SVal> Values, const Stmt *S, unsigned Count, const LocationContext *LCtx, const CallEvent *Call, InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) { @@ -1480,7 +1479,7 @@ StoreRef RegionStoreManager::invalidateRegions( } RegionBindingsRef B = getRegionBindings(store); - InvalidateRegionsWorker W(*this, StateMgr, B, Elem, Count, LCtx, IS, ITraits, + InvalidateRegionsWorker W(*this, StateMgr, B, S, Count, LCtx, IS, ITraits, Invalidated, GlobalsFilter); // Scan the bindings and generate the clusters. @@ -1500,12 +1499,12 @@ StoreRef RegionStoreManager::invalidateRegions( // TODO: This could possibly be more precise with modules. switch (GlobalsFilter) { case GFK_All: - B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, Elem, + B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, S, Count, LCtx, B, Invalidated); [[fallthrough]]; case GFK_SystemOnly: - B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, Elem, - Count, LCtx, B, Invalidated); + B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, S, Count, + LCtx, B, Invalidated); [[fallthrough]]; case GFK_None: break; diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index f1f842e..eb50547 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -152,11 +152,9 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion *region) { } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, - ConstCFGElementRef elem, + const Expr *Ex, const LocationContext *LCtx, unsigned Count) { - const Expr *Ex = dyn_cast<Expr>(elem->getAs<CFGStmt>()->getStmt()); - assert(Ex && "elem must be a CFGStmt containing an Expr"); QualType T = Ex->getType(); if (T->isNullPtrType()) @@ -168,11 +166,11 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, if (Ex->isGLValue()) T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType); - return conjureSymbolVal(SymbolTag, elem, LCtx, T, Count); + return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count); } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, - ConstCFGElementRef elem, + const Stmt *St, const LocationContext *LCtx, QualType type, unsigned count) { @@ -182,7 +180,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, count, symbolTag); + SymbolRef sym = SymMgr.conjureSymbol(St, LCtx, type, count, symbolTag); if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -190,7 +188,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(ConstCFGElementRef elem, +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt, const LocationContext *LCtx, QualType type, unsigned visitCount) { @@ -200,7 +198,7 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(ConstCFGElementRef elem, if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, visitCount); + SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount); if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -208,7 +206,14 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(ConstCFGElementRef elem, return nonloc::SymbolVal(sym); } -DefinedSVal SValBuilder::getConjuredHeapSymbolVal(ConstCFGElementRef elem, +DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E, + const LocationContext *LCtx, + unsigned VisitCount) { + QualType T = E->getType(); + return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount); +} + +DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E, const LocationContext *LCtx, QualType type, unsigned VisitCount) { @@ -220,7 +225,7 @@ DefinedSVal SValBuilder::getConjuredHeapSymbolVal(ConstCFGElementRef elem, return makeZeroVal(type).castAs<DefinedSVal>(); } - SymbolRef sym = SymMgr.conjureSymbol(elem, LCtx, type, VisitCount); + SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount); return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym)); } diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index a6ade66..a4648f5 100644 --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -82,7 +82,7 @@ void UnarySymExpr::dumpToStream(raw_ostream &os) const { void SymbolConjured::dumpToStream(raw_ostream &os) const { os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID(); - if (auto *S = getStmt()) + if (S) os << ", S" << S->getID(LCtx->getDecl()->getASTContext()); else os << ", no stmt"; diff --git a/clang/test/Analysis/PR57270.cpp b/clang/test/Analysis/PR57270.cpp deleted file mode 100644 index 7d7a658..0000000 --- a/clang/test/Analysis/PR57270.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s - -using size_t = __typeof(sizeof(int)); - -void clang_analyzer_explain(int); -void clang_analyzer_dump(int); -void *memset(void *, int, size_t); - -struct S -{ - static int a; - ~S(){}; -}; - -int S::a = 0; - -void foo() -{ - S::a = 0; - - int x = 3; - memset(&x, 1, sizeof(x)); - - S *arr = new S[x]; - delete[] arr; - - clang_analyzer_dump(S::a); // expected-warning-re{{{{derived_\$[0-9]+{conj_\$[0-9]+{int, LC[0-9]+, S[0-9]+, #[0-9]+},a}}}}} - - clang_analyzer_explain(S::a); // expected-warning-re{{{{value derived from \(symbol of type 'int' conjured at CFG element '->~S\(\) \(Implicit destructor\)'\) for global variable 'S::a'}}}} -} diff --git a/clang/test/Analysis/container-modeling.cpp b/clang/test/Analysis/container-modeling.cpp index 5dcb627..bf4a12a 100644 --- a/clang/test/Analysis/container-modeling.cpp +++ b/clang/test/Analysis/container-modeling.cpp @@ -196,7 +196,7 @@ void pop_front(std::list<int> &L, int n) { void push_back() { std::vector<int> V; V.end(); - + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); V.push_back(1); // expected-note{{Container 'V' extended to the back by 1 position}} @@ -256,7 +256,7 @@ void print_state(std::vector<int> &V) { V.cend(); clang_analyzer_printState(); - + // CHECK: "checker_messages": [ // CHECK-NEXT: { "checker": "alpha.cplusplus.ContainerModeling", "messages": [ // CHECK-NEXT: "Container Data :", diff --git a/clang/test/Analysis/dump_egraph.cpp b/clang/test/Analysis/dump_egraph.cpp index 2cea5f7..1345969 100644 --- a/clang/test/Analysis/dump_egraph.cpp +++ b/clang/test/Analysis/dump_egraph.cpp @@ -24,3 +24,4 @@ void foo() { // CHECK: \"cluster\": \"t\", \"pointer\": \"{{0x[0-9a-f]+}}\", \"items\": [\l \{ \"kind\": \"Default\", \"offset\": 0, \"value\": \"conj_$3\{int, LC5, no stmt, #1\}\" // CHECK: \"dynamic_types\": [\l \{ \"region\": \"HeapSymRegion\{conj_$1\{S *, LC1, S{{[0-9]+}}, #1\}\}\", \"dyn_type\": \"S\", \"sub_classable\": false \}\l + diff --git a/clang/test/Analysis/explain-svals.cpp b/clang/test/Analysis/explain-svals.cpp index 267980c..d1615e6 100644 --- a/clang/test/Analysis/explain-svals.cpp +++ b/clang/test/Analysis/explain-svals.cpp @@ -47,12 +47,12 @@ void test_1(int param, void *ptr) { void test_2(char *ptr, int ext) { clang_analyzer_explain((void *) "asdf"); // expected-warning-re{{{{^pointer to element of type 'char' with index 0 of string literal "asdf"$}}}} clang_analyzer_explain(strlen(ptr)); // expected-warning-re{{{{^metadata of type 'unsigned long' tied to pointee of argument 'ptr'$}}}} - clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at CFG element 'conjure\(\)'$}}}} - clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure\(\)'\) for global variable 'glob'$}}}} - clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure\(\)'\) for global variable 'glob_ptr'$}}}} + clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure\(\)'$}}}} + clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob'$}}}} + clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob_ptr'$}}}} clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^extent of pointee of argument 'ptr'$}}}} int *x = new int[ext]; - clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at CFG element 'CFGNewAllocator\(int \*\)'$}}}} + clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at statement 'new int \[ext\]'$}}}} // Sic! What gets computed is the extent of the element-region. clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^\(argument 'ext'\) \* 4$}}}} delete[] x; @@ -99,8 +99,8 @@ public: } // end of anonymous namespace void test_6() { - clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^symbol of type 'int' conjured at CFG element 'conjure_S\(\) \(CXXRecordTypedCall, \+0\)'$}}}} - clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure_S\(\) \(CXXRecordTypedCall, \)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}} + clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure_S\(\)'$}}}} + clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}} } class C_top_level { diff --git a/clang/test/Analysis/explain-svals.m b/clang/test/Analysis/explain-svals.m index e79ceab..e93258b 100644 --- a/clang/test/Analysis/explain-svals.m +++ b/clang/test/Analysis/explain-svals.m @@ -17,8 +17,8 @@ void test_1(Object *p) { clang_analyzer_explain(p); // expected-warning-re{{{{^argument 'p'$}}}} clang_analyzer_explain(p->x); // expected-warning-re{{{{^initial value of instance variable 'x' of object at argument 'p'$}}}} Object *q = [[Object alloc] init]; - clang_analyzer_explain(q); // expected-warning-re{{{{^symbol of type 'Object \*' conjured at CFG element '\[\[Object alloc\] init\]'$}}}} - clang_analyzer_explain(q->x); // expected-warning-re{{{{^initial value of instance variable 'x' of object at symbol of type 'Object \*' conjured at CFG element '\[\[Object alloc\] init\]'$}}}} + clang_analyzer_explain(q); // expected-warning-re{{{{^symbol of type 'Object \*' conjured at statement '\[\[Object alloc\] init\]'$}}}} + clang_analyzer_explain(q->x); // expected-warning-re{{{{^initial value of instance variable 'x' of object at symbol of type 'Object \*' conjured at statement '\[\[Object alloc\] init\]'$}}}} } void test_2(void) { |