Skip to content

Commit 86d479f

Browse files
T-GruberAndreas Steinhausensteakhal
authored
Adapted MemRegion::getDescriptiveName to handle ElementRegions (#85104)
Fixes #84463 Changes: - Adapted MemRegion::getDescriptiveName - Added unittest to check name for a given clang::ento::ElementRegion - Some format changes due to clang-format --------- Co-authored-by: Andreas Steinhausen <[email protected]> Co-authored-by: Balazs Benics <[email protected]>
1 parent c877294 commit 86d479f

File tree

4 files changed

+161
-6
lines changed

4 files changed

+161
-6
lines changed

clang/lib/StaticAnalyzer/Core/MemRegion.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -720,13 +720,21 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
720720
CI->getValue().toString(Idx);
721721
ArrayIndices = (llvm::Twine("[") + Idx.str() + "]" + ArrayIndices).str();
722722
}
723-
// If not a ConcreteInt, try to obtain the variable
724-
// name by calling 'getDescriptiveName' recursively.
723+
// Index is symbolic, but may have a descriptive name.
725724
else {
726-
std::string Idx = ER->getDescriptiveName(false);
727-
if (!Idx.empty()) {
728-
ArrayIndices = (llvm::Twine("[") + Idx + "]" + ArrayIndices).str();
729-
}
725+
auto SI = ER->getIndex().getAs<nonloc::SymbolVal>();
726+
if (!SI)
727+
return "";
728+
729+
const MemRegion *OR = SI->getAsSymbol()->getOriginRegion();
730+
if (!OR)
731+
return "";
732+
733+
std::string Idx = OR->getDescriptiveName(false);
734+
if (Idx.empty())
735+
return "";
736+
737+
ArrayIndices = (llvm::Twine("[") + Idx + "]" + ArrayIndices).str();
730738
}
731739
R = ER->getSuperRegion();
732740
}

clang/unittests/StaticAnalyzer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_clang_unittest(StaticAnalysisTests
1111
CallEventTest.cpp
1212
ConflictingEvalCallsTest.cpp
1313
FalsePositiveRefutationBRVisitorTest.cpp
14+
MemRegionDescriptiveNameTest.cpp
1415
NoStateChangeFuncVisitorTest.cpp
1516
ParamRegionTest.cpp
1617
RangeSetTest.cpp
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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

llvm/utils/gn/secondary/clang/unittests/StaticAnalyzer/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ unittest("StaticAnalysisTests") {
1919
"CallEventTest.cpp",
2020
"ConflictingEvalCallsTest.cpp",
2121
"FalsePositiveRefutationBRVisitorTest.cpp",
22+
"MemRegionDescriptiveNameTest.cpp",
2223
"NoStateChangeFuncVisitorTest.cpp",
2324
"ParamRegionTest.cpp",
2425
"RangeSetTest.cpp",

0 commit comments

Comments
 (0)