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 = { 42 CDM::SimpleFunc, {"reportDescriptiveName"}, 1}; 43 }; 44 45 void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer, 46 AnalyzerOptions &AnOpts) { 47 AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}}; 48 AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { 49 Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker", 50 "Desc", "DocsURI"); 51 }); 52 } 53 54 bool runChecker(StringRef Code, std::string &Output) { 55 return runCheckerOnCode<addDescriptiveNameChecker>(Code.str(), Output, 56 /*OnlyEmitWarnings=*/true); 57 } 58 59 TEST(MemRegionDescriptiveNameTest, ConcreteIntElementRegionIndex) { 60 StringRef Code = R"cpp( 61 void reportDescriptiveName(int *p); 62 const unsigned int index = 1; 63 extern int array[3]; 64 void top() { 65 reportDescriptiveName(&array[index]); 66 })cpp"; 67 68 std::string Output; 69 ASSERT_TRUE(runChecker(Code, Output)); 70 EXPECT_EQ(Output, "DescriptiveNameChecker: array[1]\n"); 71 } 72 73 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndex) { 74 StringRef Code = R"cpp( 75 void reportDescriptiveName(int *p); 76 extern unsigned int index; 77 extern int array[3]; 78 void top() { 79 reportDescriptiveName(&array[index]); 80 })cpp"; 81 82 std::string Output; 83 ASSERT_TRUE(runChecker(Code, Output)); 84 EXPECT_EQ(Output, "DescriptiveNameChecker: array[index]\n"); 85 } 86 87 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexSymbolValFails) { 88 StringRef Code = R"cpp( 89 void reportDescriptiveName(int *p); 90 extern int* ptr; 91 extern int array[3]; 92 void top() { 93 reportDescriptiveName(&array[(long)ptr]); 94 })cpp"; 95 96 std::string Output; 97 ASSERT_TRUE(runChecker(Code, Output)); 98 EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 99 } 100 101 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexOrigRegionFails) { 102 StringRef Code = R"cpp( 103 void reportDescriptiveName(int *p); 104 extern int getInt(void); 105 extern int array[3]; 106 void top() { 107 reportDescriptiveName(&array[getInt()]); 108 })cpp"; 109 110 std::string Output; 111 ASSERT_TRUE(runChecker(Code, Output)); 112 EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 113 } 114 115 TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexDescrNameFails) { 116 StringRef Code = R"cpp( 117 void reportDescriptiveName(int *p); 118 extern int *ptr; 119 extern int array[3]; 120 void top() { 121 reportDescriptiveName(&array[*ptr]); 122 })cpp"; 123 124 std::string Output; 125 ASSERT_TRUE(runChecker(Code, Output)); 126 EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); 127 } 128 129 TEST(MemRegionDescriptiveNameTest, 130 SymbolicElementRegionIndexIncorrectSymbolName) { 131 StringRef Code = R"cpp( 132 void reportDescriptiveName(int *p); 133 extern int x, y; 134 extern int array[3]; 135 void top() { 136 y = x; 137 reportDescriptiveName(&array[y]); 138 })cpp"; 139 140 std::string Output; 141 ASSERT_TRUE(runChecker(Code, Output)); 142 // FIXME: Should return array[y], but returns array[x] (OriginRegion). 143 EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n"); 144 } 145 146 } // namespace 147