xref: /llvm-project/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp (revision 86d65ae7949e0322f10e1856c5c33caa34ebfe2f)
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