158 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "Reusables.h"10 11#include "clang/Tooling/Tooling.h"12#include "gtest/gtest.h"13 14namespace clang {15namespace ento {16namespace {17 18class StoreTestConsumer : public ExprEngineConsumer {19public: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 28private:29 virtual void performTest(const Decl *D) = 0;30};31 32template <class ConsumerTy> class TestAction : public ASTFrontendAction {33public: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 it41// back from that variable. Test what happens if default bindings are used.42class 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).ResultingStore.getStore();73 EXPECT_EQ(Zero, SManager.getBinding(StX0, LX0, ASTCtxt.IntTy));74 75 // BindDefaultInitial(Zero)76 Store StY0 = SManager.BindDefaultInitial(StInit, LY0.getAsRegion(), Zero)77 .ResultingStore.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())83 .ResultingStore.getStore();84 // BindDefaultZero wipes the region with '0 S8b', not with out Zero.85 // Direct load, however, does give us back the object of the type86 // that we specify for loading.87 EXPECT_EQ(Zero, SManager.getBinding(StZ0, LZ0, ASTCtxt.IntTy));88 EXPECT_EQ(NarrowZero, *SManager.getDefaultBinding(StZ0, LZ0.getAsRegion()));89 90 // Bind(One)91 Store StX1 = SManager.Bind(StInit, LX1, One).ResultingStore.getStore();92 EXPECT_EQ(One, SManager.getBinding(StX1, LX1, ASTCtxt.IntTy));93 94 // BindDefaultInitial(One)95 Store StY1 = SManager.BindDefaultInitial(StInit, LY1.getAsRegion(), One)96 .ResultingStore.getStore();97 EXPECT_EQ(One, SManager.getBinding(StY1, LY1, ASTCtxt.IntTy));98 EXPECT_EQ(One, *SManager.getDefaultBinding(StY1, LY1.getAsRegion()));99 }100 101public:102 using StoreTestConsumer::StoreTestConsumer;103};104 105TEST(Store, VariableBind) {106 EXPECT_TRUE(tooling::runToolOnCode(107 std::make_unique<TestAction<VariableBindConsumer>>(),108 "void foo() { int x0, y0, z0, x1, y1; }"));109}110 111class LiteralCompoundConsumer : public StoreTestConsumer {112 void performTest(const Decl *D) override {113 StoreManager &SManager = Eng.getStoreManager();114 SValBuilder &Builder = Eng.getSValBuilder();115 MemRegionManager &MRManager = SManager.getRegionManager();116 ASTContext &ASTCtxt = Eng.getContext();117 118 using namespace ast_matchers;119 120 const auto *CL = findNode<CompoundLiteralExpr>(D, compoundLiteralExpr());121 122 const StackFrameContext *SFC =123 Eng.getAnalysisDeclContextManager().getStackFrame(D);124 125 QualType Int = ASTCtxt.IntTy;126 127 // Get region for 'test'128 const SubRegion *CLRegion = MRManager.getCompoundLiteralRegion(CL, SFC);129 130 // Get value for 'test[0]'131 NonLoc Zero = Builder.makeIntVal(0, false);132 loc::MemRegionVal ZeroElement(133 MRManager.getElementRegion(ASTCtxt.IntTy, Zero, CLRegion, ASTCtxt));134 135 Store StInit = SManager.getInitialStore(SFC).getStore();136 // Let's bind constant 1 to 'test[0]'137 SVal One = Builder.makeIntVal(1, Int);138 Store StX =139 SManager.Bind(StInit, ZeroElement, One).ResultingStore.getStore();140 141 // And make sure that we can read this binding back as it was142 EXPECT_EQ(One, SManager.getBinding(StX, ZeroElement, Int));143 }144 145public:146 using StoreTestConsumer::StoreTestConsumer;147};148 149TEST(Store, LiteralCompound) {150 EXPECT_TRUE(tooling::runToolOnCode(151 std::make_unique<TestAction<LiteralCompoundConsumer>>(),152 "void foo() { int *test = (int[]){ 1, 2, 3 }; }", "input.c"));153}154 155} // namespace156} // namespace ento157} // namespace clang158