summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/StaticAnalyzer/Core/RegionStore.cpp5
-rw-r--r--clang/test/Analysis/string.c6
-rw-r--r--clang/unittests/StaticAnalyzer/CMakeLists.txt1
-rw-r--r--clang/unittests/StaticAnalyzer/StoreTest.cpp105
4 files changed, 116 insertions, 1 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 1782d46e614..ffb25dc3d16 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1927,7 +1927,10 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
const VarRegion *R) {
// Check if the region has a binding.
- if (const Optional<SVal> &V = B.getDirectBinding(R))
+ if (Optional<SVal> V = B.getDirectBinding(R))
+ return *V;
+
+ if (Optional<SVal> V = B.getDefaultBinding(R))
return *V;
// Lazily derive a value for the VarRegion.
diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c
index 4cb2e6c7875..107c199c68d 100644
--- a/clang/test/Analysis/string.c
+++ b/clang/test/Analysis/string.c
@@ -1554,3 +1554,9 @@ void memset28() {
// This should be true.
clang_analyzer_eval(x == 0x101); // expected-warning{{UNKNOWN}}
}
+
+void memset29_plain_int_zero() {
+ short x;
+ memset(&x, 0, sizeof(short));
+ clang_analyzer_eval(x == 0); // expected-warning{{TRUE}}
+}
diff --git a/clang/unittests/StaticAnalyzer/CMakeLists.txt b/clang/unittests/StaticAnalyzer/CMakeLists.txt
index 000c9aea94f..5348a0a2bc8 100644
--- a/clang/unittests/StaticAnalyzer/CMakeLists.txt
+++ b/clang/unittests/StaticAnalyzer/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(StaticAnalysisTests
AnalyzerOptionsTest.cpp
+ StoreTest.cpp
RegisterCustomCheckersTest.cpp
SymbolReaperTest.cpp
)
diff --git a/clang/unittests/StaticAnalyzer/StoreTest.cpp b/clang/unittests/StaticAnalyzer/StoreTest.cpp
new file mode 100644
index 00000000000..ab8c781e328
--- /dev/null
+++ b/clang/unittests/StaticAnalyzer/StoreTest.cpp
@@ -0,0 +1,105 @@
+//===- unittests/StaticAnalyzer/StoreTest.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Reusables.h"
+
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+// Test that we can put a value into an int-type variable and load it
+// back from that variable. Test what happens if default bindings are used.
+class VariableBindConsumer : public ExprEngineConsumer {
+ void performTest(const Decl *D) {
+ StoreManager &StMgr = Eng.getStoreManager();
+ SValBuilder &SVB = Eng.getSValBuilder();
+ MemRegionManager &MRMgr = StMgr.getRegionManager();
+ const ASTContext &ACtx = Eng.getContext();
+
+ const auto *VDX0 = findDeclByName<VarDecl>(D, "x0");
+ const auto *VDY0 = findDeclByName<VarDecl>(D, "y0");
+ const auto *VDZ0 = findDeclByName<VarDecl>(D, "z0");
+ const auto *VDX1 = findDeclByName<VarDecl>(D, "x1");
+ const auto *VDY1 = findDeclByName<VarDecl>(D, "y1");
+ assert(VDX0 && VDY0 && VDZ0 && VDX1 && VDY1);
+
+ const StackFrameContext *SFC =
+ Eng.getAnalysisDeclContextManager().getStackFrame(D);
+
+ Loc LX0 = loc::MemRegionVal(MRMgr.getVarRegion(VDX0, SFC));
+ Loc LY0 = loc::MemRegionVal(MRMgr.getVarRegion(VDY0, SFC));
+ Loc LZ0 = loc::MemRegionVal(MRMgr.getVarRegion(VDZ0, SFC));
+ Loc LX1 = loc::MemRegionVal(MRMgr.getVarRegion(VDX1, SFC));
+ Loc LY1 = loc::MemRegionVal(MRMgr.getVarRegion(VDY1, SFC));
+
+ Store StInit = StMgr.getInitialStore(SFC).getStore();
+ SVal Zero = SVB.makeZeroVal(ACtx.IntTy);
+ SVal One = SVB.makeIntVal(1, ACtx.IntTy);
+ SVal NarrowZero = SVB.makeZeroVal(ACtx.CharTy);
+
+ // Bind(Zero)
+ Store StX0 =
+ StMgr.Bind(StInit, LX0, Zero).getStore();
+ ASSERT_EQ(Zero, StMgr.getBinding(StX0, LX0, ACtx.IntTy));
+
+ // BindDefaultInitial(Zero)
+ Store StY0 =
+ StMgr.BindDefaultInitial(StInit, LY0.getAsRegion(), Zero).getStore();
+ ASSERT_EQ(Zero, StMgr.getBinding(StY0, LY0, ACtx.IntTy));
+ ASSERT_EQ(Zero, *StMgr.getDefaultBinding(StY0, LY0.getAsRegion()));
+
+ // BindDefaultZero()
+ Store StZ0 =
+ StMgr.BindDefaultZero(StInit, LZ0.getAsRegion()).getStore();
+ // BindDefaultZero wipes the region with '0 S8b', not with out Zero.
+ // Direct load, however, does give us back the object of the type
+ // that we specify for loading.
+ ASSERT_EQ(Zero, StMgr.getBinding(StZ0, LZ0, ACtx.IntTy));
+ ASSERT_EQ(NarrowZero, *StMgr.getDefaultBinding(StZ0, LZ0.getAsRegion()));
+
+ // Bind(One)
+ Store StX1 =
+ StMgr.Bind(StInit, LX1, One).getStore();
+ ASSERT_EQ(One, StMgr.getBinding(StX1, LX1, ACtx.IntTy));
+
+ // BindDefaultInitial(One)
+ Store StY1 =
+ StMgr.BindDefaultInitial(StInit, LY1.getAsRegion(), One).getStore();
+ ASSERT_EQ(One, StMgr.getBinding(StY1, LY1, ACtx.IntTy));
+ ASSERT_EQ(One, *StMgr.getDefaultBinding(StY1, LY1.getAsRegion()));
+ }
+
+public:
+ VariableBindConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ for (const auto *D : DG)
+ performTest(D);
+ return true;
+ }
+};
+
+class VariableBindAction : public ASTFrontendAction {
+public:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ return llvm::make_unique<VariableBindConsumer>(Compiler);
+ }
+};
+
+TEST(Store, VariableBind) {
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new VariableBindAction, "void foo() { int x0, y0, z0, x1, y1; }"));
+}
+
+} // namespace
+} // namespace ento
+} // namespace clang
OpenPOWER on IntegriCloud