xref: /llvm-project/clang/unittests/StaticAnalyzer/StoreTest.cpp (revision bd06c417e6c717cbe33b566d7bbaf27fb47e763a)
1 //===- unittests/StaticAnalyzer/StoreTest.cpp -----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Reusables.h"
10 
11 #include "clang/Tooling/Tooling.h"
12 #include "gtest/gtest.h"
13 
14 namespace clang {
15 namespace ento {
16 namespace {
17 
18 class StoreTestConsumer : public ExprEngineConsumer {
19 public:
StoreTestConsumer(CompilerInstance & C)20   StoreTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
21 
HandleTopLevelDecl(DeclGroupRef DG)22   bool HandleTopLevelDecl(DeclGroupRef DG) override {
23     for (const auto *D : DG)
24       performTest(D);
25     return true;
26   }
27 
28 private:
29   virtual void performTest(const Decl *D) = 0;
30 };
31 
32 template <class ConsumerTy> class TestAction : public ASTFrontendAction {
33 public:
CreateASTConsumer(CompilerInstance & Compiler,StringRef File)34   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
35                                                  StringRef File) override {
36     return std::make_unique<ConsumerTy>(Compiler);
37   }
38 };
39 
40 // Test that we can put a value into an int-type variable and load it
41 // back from that variable. Test what happens if default bindings are used.
42 class VariableBindConsumer : public StoreTestConsumer {
performTest(const Decl * D)43   void performTest(const Decl *D) override {
44     StoreManager &SManager = Eng.getStoreManager();
45     SValBuilder &Builder = Eng.getSValBuilder();
46     MemRegionManager &MRManager = SManager.getRegionManager();
47     const ASTContext &ASTCtxt = Eng.getContext();
48 
49     const auto *VDX0 = findDeclByName<VarDecl>(D, "x0");
50     const auto *VDY0 = findDeclByName<VarDecl>(D, "y0");
51     const auto *VDZ0 = findDeclByName<VarDecl>(D, "z0");
52     const auto *VDX1 = findDeclByName<VarDecl>(D, "x1");
53     const auto *VDY1 = findDeclByName<VarDecl>(D, "y1");
54 
55     ASSERT_TRUE(VDX0 && VDY0 && VDZ0 && VDX1 && VDY1);
56 
57     const StackFrameContext *SFC =
58         Eng.getAnalysisDeclContextManager().getStackFrame(D);
59 
60     Loc LX0 = loc::MemRegionVal(MRManager.getVarRegion(VDX0, SFC));
61     Loc LY0 = loc::MemRegionVal(MRManager.getVarRegion(VDY0, SFC));
62     Loc LZ0 = loc::MemRegionVal(MRManager.getVarRegion(VDZ0, SFC));
63     Loc LX1 = loc::MemRegionVal(MRManager.getVarRegion(VDX1, SFC));
64     Loc LY1 = loc::MemRegionVal(MRManager.getVarRegion(VDY1, SFC));
65 
66     Store StInit = SManager.getInitialStore(SFC).getStore();
67     SVal Zero = Builder.makeZeroVal(ASTCtxt.IntTy);
68     SVal One = Builder.makeIntVal(1, ASTCtxt.IntTy);
69     SVal NarrowZero = Builder.makeZeroVal(ASTCtxt.CharTy);
70 
71     // Bind(Zero)
72     Store StX0 = SManager.Bind(StInit, LX0, Zero).getStore();
73     EXPECT_EQ(Zero, SManager.getBinding(StX0, LX0, ASTCtxt.IntTy));
74 
75     // BindDefaultInitial(Zero)
76     Store StY0 =
77         SManager.BindDefaultInitial(StInit, LY0.getAsRegion(), Zero).getStore();
78     EXPECT_EQ(Zero, SManager.getBinding(StY0, LY0, ASTCtxt.IntTy));
79     EXPECT_EQ(Zero, *SManager.getDefaultBinding(StY0, LY0.getAsRegion()));
80 
81     // BindDefaultZero()
82     Store StZ0 = SManager.BindDefaultZero(StInit, LZ0.getAsRegion()).getStore();
83     // BindDefaultZero wipes the region with '0 S8b', not with out Zero.
84     // Direct load, however, does give us back the object of the type
85     // that we specify for loading.
86     EXPECT_EQ(Zero, SManager.getBinding(StZ0, LZ0, ASTCtxt.IntTy));
87     EXPECT_EQ(NarrowZero, *SManager.getDefaultBinding(StZ0, LZ0.getAsRegion()));
88 
89     // Bind(One)
90     Store StX1 = SManager.Bind(StInit, LX1, One).getStore();
91     EXPECT_EQ(One, SManager.getBinding(StX1, LX1, ASTCtxt.IntTy));
92 
93     // BindDefaultInitial(One)
94     Store StY1 =
95         SManager.BindDefaultInitial(StInit, LY1.getAsRegion(), One).getStore();
96     EXPECT_EQ(One, SManager.getBinding(StY1, LY1, ASTCtxt.IntTy));
97     EXPECT_EQ(One, *SManager.getDefaultBinding(StY1, LY1.getAsRegion()));
98   }
99 
100 public:
101   using StoreTestConsumer::StoreTestConsumer;
102 };
103 
TEST(Store,VariableBind)104 TEST(Store, VariableBind) {
105   EXPECT_TRUE(tooling::runToolOnCode(
106       std::make_unique<TestAction<VariableBindConsumer>>(),
107       "void foo() { int x0, y0, z0, x1, y1; }"));
108 }
109 
110 class LiteralCompoundConsumer : public StoreTestConsumer {
performTest(const Decl * D)111   void performTest(const Decl *D) override {
112     StoreManager &SManager = Eng.getStoreManager();
113     SValBuilder &Builder = Eng.getSValBuilder();
114     MemRegionManager &MRManager = SManager.getRegionManager();
115     ASTContext &ASTCtxt = Eng.getContext();
116 
117     using namespace ast_matchers;
118 
119     const auto *CL = findNode<CompoundLiteralExpr>(D, compoundLiteralExpr());
120 
121     const StackFrameContext *SFC =
122         Eng.getAnalysisDeclContextManager().getStackFrame(D);
123 
124     QualType Int = ASTCtxt.IntTy;
125 
126     // Get region for 'test'
127     const SubRegion *CLRegion = MRManager.getCompoundLiteralRegion(CL, SFC);
128 
129     // Get value for 'test[0]'
130     NonLoc Zero = Builder.makeIntVal(0, false);
131     loc::MemRegionVal ZeroElement(
132         MRManager.getElementRegion(ASTCtxt.IntTy, Zero, CLRegion, ASTCtxt));
133 
134     Store StInit = SManager.getInitialStore(SFC).getStore();
135     // Let's bind constant 1 to 'test[0]'
136     SVal One = Builder.makeIntVal(1, Int);
137     Store StX = SManager.Bind(StInit, ZeroElement, One).getStore();
138 
139     // And make sure that we can read this binding back as it was
140     EXPECT_EQ(One, SManager.getBinding(StX, ZeroElement, Int));
141   }
142 
143 public:
144   using StoreTestConsumer::StoreTestConsumer;
145 };
146 
TEST(Store,LiteralCompound)147 TEST(Store, LiteralCompound) {
148   EXPECT_TRUE(tooling::runToolOnCode(
149       std::make_unique<TestAction<LiteralCompoundConsumer>>(),
150       "void foo() { int *test = (int[]){ 1, 2, 3 }; }", "input.c"));
151 }
152 
153 } // namespace
154 } // namespace ento
155 } // namespace clang
156