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 16 using namespace clang; 17 using namespace ento; 18 19 namespace { 20 21 class DescriptiveNameChecker : public Checker<check::PreCall> { 22 public: 23 void checkPreCall(const CallEvent &Call, CheckerContext &C) const { 24 if (!HandlerFn.matches(Call)) 25 return; 26 27 const MemRegion *ArgReg = Call.getArgSVal(0).getAsRegion(); 28 assert(ArgReg && "expecting a location as the first argument"); 29 30 auto DescriptiveName = ArgReg->getDescriptiveName(/*UseQuotes=*/false); 31 if (ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState())) { 32 auto Report = 33 std::make_unique<PathSensitiveBugReport>(Bug, DescriptiveName, Node); 34 C.emitReport(std::move(Report)); 35 } 36 } 37 38 private: 39 const BugType Bug{this, "DescriptiveNameBug"}; 40 const CallDescription HandlerFn = { 41 CDM::SimpleFunc, {"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 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 TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperElementReg) { 146 StringRef Code = R"cpp( 147 void reportDescriptiveName(int *p); 148 struct val_struct { int val; }; 149 extern struct val_struct val_struct_array[3]; 150 void top() { 151 reportDescriptiveName(&val_struct_array[0].val); 152 })cpp"; 153 154 std::string Output; 155 ASSERT_TRUE(runChecker(Code, Output)); 156 EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[0].val\n"); 157 } 158 159 TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperMultidimElementReg) { 160 StringRef Code = R"cpp( 161 void reportDescriptiveName(int *p); 162 struct val_struct { int val; }; 163 extern struct val_struct val_struct_array[3][4]; 164 void top() { 165 reportDescriptiveName(&val_struct_array[1][2].val); 166 })cpp"; 167 168 std::string Output; 169 ASSERT_TRUE(runChecker(Code, Output)); 170 EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[1][2].val\n"); 171 } 172 173 } // namespace 174