186d479fdST-Gruber //===- MemRegionDescriptiveNameTest.cpp -----------------------------------===// 286d479fdST-Gruber // 386d479fdST-Gruber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 486d479fdST-Gruber // See https://llvm.org/LICENSE.txt for license information. 586d479fdST-Gruber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 686d479fdST-Gruber // 786d479fdST-Gruber //===----------------------------------------------------------------------===// 886d479fdST-Gruber 986d479fdST-Gruber #include "CheckerRegistration.h" 1086d479fdST-Gruber #include "clang/StaticAnalyzer/Core/Checker.h" 1186d479fdST-Gruber #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 1286d479fdST-Gruber #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 1386d479fdST-Gruber #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" 1486d479fdST-Gruber #include "gtest/gtest.h" 1586d479fdST-Gruber 1686d479fdST-Gruber using namespace clang; 1786d479fdST-Gruber using namespace ento; 1886d479fdST-Gruber 1986d479fdST-Gruber namespace { 2086d479fdST-Gruber 2186d479fdST-Gruber class DescriptiveNameChecker : public Checker<check::PreCall> { 2286d479fdST-Gruber public: 2386d479fdST-Gruber void checkPreCall(const CallEvent &Call, CheckerContext &C) const { 2486d479fdST-Gruber if (!HandlerFn.matches(Call)) 2586d479fdST-Gruber return; 2686d479fdST-Gruber 2786d479fdST-Gruber const MemRegion *ArgReg = Call.getArgSVal(0).getAsRegion(); 2886d479fdST-Gruber assert(ArgReg && "expecting a location as the first argument"); 2986d479fdST-Gruber 3086d479fdST-Gruber auto DescriptiveName = ArgReg->getDescriptiveName(/*UseQuotes=*/false); 3186d479fdST-Gruber if (ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState())) { 3286d479fdST-Gruber auto Report = 3386d479fdST-Gruber std::make_unique<PathSensitiveBugReport>(Bug, DescriptiveName, Node); 3486d479fdST-Gruber C.emitReport(std::move(Report)); 3586d479fdST-Gruber } 3686d479fdST-Gruber } 3786d479fdST-Gruber 3886d479fdST-Gruber private: 3986d479fdST-Gruber const BugType Bug{this, "DescriptiveNameBug"}; 4058bad286SDonát Nagy const CallDescription HandlerFn = { 4158bad286SDonát Nagy CDM::SimpleFunc, {"reportDescriptiveName"}, 1}; 4286d479fdST-Gruber }; 4386d479fdST-Gruber 4486d479fdST-Gruber void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer, 4586d479fdST-Gruber AnalyzerOptions &AnOpts) { 4686d479fdST-Gruber AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}}; 4786d479fdST-Gruber AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { 4886d479fdST-Gruber Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker", 4986d479fdST-Gruber "Desc", "DocsURI"); 5086d479fdST-Gruber }); 5186d479fdST-Gruber } 5286d479fdST-Gruber 5386d479fdST-Gruber bool runChecker(StringRef Code, std::string &Output) { 5486d479fdST-Gruber return runCheckerOnCode<addDescriptiveNameChecker>(Code.str(), Output, 5586d479fdST-Gruber /*OnlyEmitWarnings=*/true); 5686d479fdST-Gruber } 5786d479fdST-Gruber 5886d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, ConcreteIntElementRegionIndex) { 5986d479fdST-Gruber StringRef Code = R"cpp( 6086d479fdST-Gruber void reportDescriptiveName(int *p); 6186d479fdST-Gruber const unsigned int index = 1; 6286d479fdST-Gruber extern int array[3]; 6386d479fdST-Gruber void top() { 6486d479fdST-Gruber reportDescriptiveName(&array[index]); 6586d479fdST-Gruber })cpp"; 6686d479fdST-Gruber 6786d479fdST-Gruber std::string Output; 6886d479fdST-Gruber ASSERT_TRUE(runChecker(Code, Output)); 6986d479fdST-Gruber EXPECT_EQ(Output, "DescriptiveNameChecker: array[1]\n"); 7086d479fdST-Gruber } 7186d479fdST-Gruber 7286d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndex) { 7386d479fdST-Gruber StringRef Code = R"cpp( 7486d479fdST-Gruber void reportDescriptiveName(int *p); 7586d479fdST-Gruber extern unsigned int index; 7686d479fdST-Gruber extern int array[3]; 7786d479fdST-Gruber void top() { 7886d479fdST-Gruber reportDescriptiveName(&array[index]); 7986d479fdST-Gruber })cpp"; 8086d479fdST-Gruber 8186d479fdST-Gruber std::string Output; 8286d479fdST-Gruber ASSERT_TRUE(runChecker(Code, Output)); 8386d479fdST-Gruber EXPECT_EQ(Output, "DescriptiveNameChecker: array[index]\n"); 8486d479fdST-Gruber } 8586d479fdST-Gruber 8686d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexSymbolValFails) { 8786d479fdST-Gruber StringRef Code = R"cpp( 8886d479fdST-Gruber void reportDescriptiveName(int *p); 8986d479fdST-Gruber extern int* ptr; 9086d479fdST-Gruber extern int array[3]; 9186d479fdST-Gruber void top() { 92f31b197dSMartin Storsjö reportDescriptiveName(&array[(long long)ptr]); 9386d479fdST-Gruber })cpp"; 9486d479fdST-Gruber 9586d479fdST-Gruber std::string Output; 9686d479fdST-Gruber ASSERT_TRUE(runChecker(Code, Output)); 9786d479fdST-Gruber EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 9886d479fdST-Gruber } 9986d479fdST-Gruber 10086d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexOrigRegionFails) { 10186d479fdST-Gruber StringRef Code = R"cpp( 10286d479fdST-Gruber void reportDescriptiveName(int *p); 10386d479fdST-Gruber extern int getInt(void); 10486d479fdST-Gruber extern int array[3]; 10586d479fdST-Gruber void top() { 10686d479fdST-Gruber reportDescriptiveName(&array[getInt()]); 10786d479fdST-Gruber })cpp"; 10886d479fdST-Gruber 10986d479fdST-Gruber std::string Output; 11086d479fdST-Gruber ASSERT_TRUE(runChecker(Code, Output)); 11186d479fdST-Gruber EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 11286d479fdST-Gruber } 11386d479fdST-Gruber 11486d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexDescrNameFails) { 11586d479fdST-Gruber StringRef Code = R"cpp( 11686d479fdST-Gruber void reportDescriptiveName(int *p); 11786d479fdST-Gruber extern int *ptr; 11886d479fdST-Gruber extern int array[3]; 11986d479fdST-Gruber void top() { 12086d479fdST-Gruber reportDescriptiveName(&array[*ptr]); 12186d479fdST-Gruber })cpp"; 12286d479fdST-Gruber 12386d479fdST-Gruber std::string Output; 12486d479fdST-Gruber ASSERT_TRUE(runChecker(Code, Output)); 12586d479fdST-Gruber EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 12686d479fdST-Gruber } 12786d479fdST-Gruber 12886d479fdST-Gruber TEST(MemRegionDescriptiveNameTest, 12986d479fdST-Gruber SymbolicElementRegionIndexIncorrectSymbolName) { 13086d479fdST-Gruber StringRef Code = R"cpp( 13186d479fdST-Gruber void reportDescriptiveName(int *p); 13286d479fdST-Gruber extern int x, y; 13386d479fdST-Gruber extern int array[3]; 13486d479fdST-Gruber void top() { 13586d479fdST-Gruber y = x; 13686d479fdST-Gruber reportDescriptiveName(&array[y]); 13786d479fdST-Gruber })cpp"; 13886d479fdST-Gruber 13986d479fdST-Gruber std::string Output; 14086d479fdST-Gruber ASSERT_TRUE(runChecker(Code, Output)); 14186d479fdST-Gruber // FIXME: Should return array[y], but returns array[x] (OriginRegion). 14286d479fdST-Gruber EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n"); 14386d479fdST-Gruber } 14486d479fdST-Gruber 145*86d65ae7ST-Gruber TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperElementReg) { 146*86d65ae7ST-Gruber StringRef Code = R"cpp( 147*86d65ae7ST-Gruber void reportDescriptiveName(int *p); 148*86d65ae7ST-Gruber struct val_struct { int val; }; 149*86d65ae7ST-Gruber extern struct val_struct val_struct_array[3]; 150*86d65ae7ST-Gruber void top() { 151*86d65ae7ST-Gruber reportDescriptiveName(&val_struct_array[0].val); 152*86d65ae7ST-Gruber })cpp"; 153*86d65ae7ST-Gruber 154*86d65ae7ST-Gruber std::string Output; 155*86d65ae7ST-Gruber ASSERT_TRUE(runChecker(Code, Output)); 156*86d65ae7ST-Gruber EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[0].val\n"); 157*86d65ae7ST-Gruber } 158*86d65ae7ST-Gruber 159*86d65ae7ST-Gruber TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperMultidimElementReg) { 160*86d65ae7ST-Gruber StringRef Code = R"cpp( 161*86d65ae7ST-Gruber void reportDescriptiveName(int *p); 162*86d65ae7ST-Gruber struct val_struct { int val; }; 163*86d65ae7ST-Gruber extern struct val_struct val_struct_array[3][4]; 164*86d65ae7ST-Gruber void top() { 165*86d65ae7ST-Gruber reportDescriptiveName(&val_struct_array[1][2].val); 166*86d65ae7ST-Gruber })cpp"; 167*86d65ae7ST-Gruber 168*86d65ae7ST-Gruber std::string Output; 169*86d65ae7ST-Gruber ASSERT_TRUE(runChecker(Code, Output)); 170*86d65ae7ST-Gruber EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[1][2].val\n"); 171*86d65ae7ST-Gruber } 172*86d65ae7ST-Gruber 17386d479fdST-Gruber } // namespace 174