1 //===- MemRegionDescriptiveNameTest.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 "CheckerRegistration.h" 10 #include "clang/StaticAnalyzer/Core/Checker.h" 11 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 12 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 13 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" 14 #include "gtest/gtest.h" 15 #include <fstream> 16 17 using namespace clang; 18 using namespace ento; 19 20 namespace { 21 22 class DescriptiveNameChecker : public Checker<check::PreCall> { 23 public: 24 void checkPreCall(const CallEvent &Call, CheckerContext &C) const { 25 if (!HandlerFn.matches(Call)) 26 return; 27 28 const MemRegion *ArgReg = Call.getArgSVal(0).getAsRegion(); 29 assert(ArgReg && "expecting a location as the first argument"); 30 31 auto DescriptiveName = ArgReg->getDescriptiveName(/*UseQuotes=*/false); 32 if (ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState())) { 33 auto Report = 34 std::make_unique<PathSensitiveBugReport>(Bug, DescriptiveName, Node); 35 C.emitReport(std::move(Report)); 36 } 37 } 38 39 private: 40 const BugType Bug{this, "DescriptiveNameBug"}; 41 const CallDescription HandlerFn = {{"reportDescriptiveName"}, 1}; 42 }; 43 44 void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer, 45 AnalyzerOptions &AnOpts) { 46 AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}}; 47 AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { 48 Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker", 49 "Desc", "DocsURI"); 50 }); 51 } 52 53 bool runChecker(StringRef Code, std::string &Output) { 54 return runCheckerOnCode<addDescriptiveNameChecker>(Code.str(), Output, 55 /*OnlyEmitWarnings=*/true); 56 } 57 58 TEST(MemRegionDescriptiveNameTest, ConcreteIntElementRegionIndex) { 59 StringRef Code = R"cpp( 60 void reportDescriptiveName(int *p); 61 const unsigned int index = 1; 62 extern int array[3]; 63 void top() { 64 reportDescriptiveName(&array[index]); 65 })cpp"; 66 67 std::string Output; 68 ASSERT_TRUE(runChecker(Code, Output)); 69 EXPECT_EQ(Output, "DescriptiveNameChecker: array[1]\n"); 70 } 71 72 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndex) { 73 StringRef Code = R"cpp( 74 void reportDescriptiveName(int *p); 75 extern unsigned int index; 76 extern int array[3]; 77 void top() { 78 reportDescriptiveName(&array[index]); 79 })cpp"; 80 81 std::string Output; 82 ASSERT_TRUE(runChecker(Code, Output)); 83 EXPECT_EQ(Output, "DescriptiveNameChecker: array[index]\n"); 84 } 85 86 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexSymbolValFails) { 87 StringRef Code = R"cpp( 88 void reportDescriptiveName(int *p); 89 extern int* ptr; 90 extern int array[3]; 91 void top() { 92 reportDescriptiveName(&array[(long)ptr]); 93 })cpp"; 94 95 std::string Output; 96 ASSERT_TRUE(runChecker(Code, Output)); 97 EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 98 } 99 100 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexOrigRegionFails) { 101 StringRef Code = R"cpp( 102 void reportDescriptiveName(int *p); 103 extern int getInt(void); 104 extern int array[3]; 105 void top() { 106 reportDescriptiveName(&array[getInt()]); 107 })cpp"; 108 109 std::string Output; 110 ASSERT_TRUE(runChecker(Code, Output)); 111 EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 112 } 113 114 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexDescrNameFails) { 115 StringRef Code = R"cpp( 116 void reportDescriptiveName(int *p); 117 extern int *ptr; 118 extern int array[3]; 119 void top() { 120 reportDescriptiveName(&array[*ptr]); 121 })cpp"; 122 123 std::string Output; 124 ASSERT_TRUE(runChecker(Code, Output)); 125 EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 126 } 127 128 TEST(MemRegionDescriptiveNameTest, 129 SymbolicElementRegionIndexIncorrectSymbolName) { 130 StringRef Code = R"cpp( 131 void reportDescriptiveName(int *p); 132 extern int x, y; 133 extern int array[3]; 134 void top() { 135 y = x; 136 reportDescriptiveName(&array[y]); 137 })cpp"; 138 139 std::string Output; 140 ASSERT_TRUE(runChecker(Code, Output)); 141 // FIXME: Should return array[y], but returns array[x] (OriginRegion). 142 EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n"); 143 } 144 145 } // namespace 146