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: 20 StoreTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {} 21 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: 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 { 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 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 { 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 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