| //===- MemRegionDescriptiveNameTest.cpp -----------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CheckerRegistration.h" |
| #include "clang/StaticAnalyzer/Core/Checker.h" |
| #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" |
| #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
| #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" |
| #include "gtest/gtest.h" |
| |
| using namespace clang; |
| using namespace ento; |
| |
| namespace { |
| |
| class DescriptiveNameChecker : public Checker<check::PreCall> { |
| public: |
| void checkPreCall(const CallEvent &Call, CheckerContext &C) const { |
| if (!HandlerFn.matches(Call)) |
| return; |
| |
| const MemRegion *ArgReg = Call.getArgSVal(0).getAsRegion(); |
| assert(ArgReg && "expecting a location as the first argument"); |
| |
| auto DescriptiveName = ArgReg->getDescriptiveName(/*UseQuotes=*/false); |
| if (ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState())) { |
| auto Report = |
| std::make_unique<PathSensitiveBugReport>(Bug, DescriptiveName, Node); |
| C.emitReport(std::move(Report)); |
| } |
| } |
| |
| private: |
| const BugType Bug{this, "DescriptiveNameBug"}; |
| const CallDescription HandlerFn = { |
| CDM::SimpleFunc, {"reportDescriptiveName"}, 1}; |
| }; |
| |
| void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer, |
| AnalyzerOptions &AnOpts) { |
| AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}}; |
| AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { |
| Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker", |
| "Desc", "DocsURI"); |
| }); |
| } |
| |
| bool runChecker(StringRef Code, std::string &Output) { |
| return runCheckerOnCode<addDescriptiveNameChecker>(Code.str(), Output, |
| /*OnlyEmitWarnings=*/true); |
| } |
| |
| TEST(MemRegionDescriptiveNameTest, ConcreteIntElementRegionIndex) { |
| StringRef Code = R"cpp( |
| void reportDescriptiveName(int *p); |
| const unsigned int index = 1; |
| extern int array[3]; |
| void top() { |
| reportDescriptiveName(&array[index]); |
| })cpp"; |
| |
| std::string Output; |
| ASSERT_TRUE(runChecker(Code, Output)); |
| EXPECT_EQ(Output, "DescriptiveNameChecker: array[1]\n"); |
| } |
| |
| TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndex) { |
| StringRef Code = R"cpp( |
| void reportDescriptiveName(int *p); |
| extern unsigned int index; |
| extern int array[3]; |
| void top() { |
| reportDescriptiveName(&array[index]); |
| })cpp"; |
| |
| std::string Output; |
| ASSERT_TRUE(runChecker(Code, Output)); |
| EXPECT_EQ(Output, "DescriptiveNameChecker: array[index]\n"); |
| } |
| |
| TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexSymbolValFails) { |
| StringRef Code = R"cpp( |
| void reportDescriptiveName(int *p); |
| extern int* ptr; |
| extern int array[3]; |
| void top() { |
| reportDescriptiveName(&array[(long long)ptr]); |
| })cpp"; |
| |
| std::string Output; |
| ASSERT_TRUE(runChecker(Code, Output)); |
| EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); |
| } |
| |
| TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexOrigRegionFails) { |
| StringRef Code = R"cpp( |
| void reportDescriptiveName(int *p); |
| extern int getInt(void); |
| extern int array[3]; |
| void top() { |
| reportDescriptiveName(&array[getInt()]); |
| })cpp"; |
| |
| std::string Output; |
| ASSERT_TRUE(runChecker(Code, Output)); |
| EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); |
| } |
| |
| TEST(MemRegionDescriptiveNameTest, SymbolicElementRegionIndexDescrNameFails) { |
| StringRef Code = R"cpp( |
| void reportDescriptiveName(int *p); |
| extern int *ptr; |
| extern int array[3]; |
| void top() { |
| reportDescriptiveName(&array[*ptr]); |
| })cpp"; |
| |
| std::string Output; |
| ASSERT_TRUE(runChecker(Code, Output)); |
| EXPECT_EQ(Output, "DescriptiveNameChecker: \n"); |
| } |
| |
| TEST(MemRegionDescriptiveNameTest, |
| SymbolicElementRegionIndexIncorrectSymbolName) { |
| StringRef Code = R"cpp( |
| void reportDescriptiveName(int *p); |
| extern int x, y; |
| extern int array[3]; |
| void top() { |
| y = x; |
| reportDescriptiveName(&array[y]); |
| })cpp"; |
| |
| std::string Output; |
| ASSERT_TRUE(runChecker(Code, Output)); |
| // FIXME: Should return array[y], but returns array[x] (OriginRegion). |
| EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n"); |
| } |
| |
| TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperElementReg) { |
| StringRef Code = R"cpp( |
| void reportDescriptiveName(int *p); |
| struct val_struct { int val; }; |
| extern struct val_struct val_struct_array[3]; |
| void top() { |
| reportDescriptiveName(&val_struct_array[0].val); |
| })cpp"; |
| |
| std::string Output; |
| ASSERT_TRUE(runChecker(Code, Output)); |
| EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[0].val\n"); |
| } |
| |
| TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperMultidimElementReg) { |
| StringRef Code = R"cpp( |
| void reportDescriptiveName(int *p); |
| struct val_struct { int val; }; |
| extern struct val_struct val_struct_array[3][4]; |
| void top() { |
| reportDescriptiveName(&val_struct_array[1][2].val); |
| })cpp"; |
| |
| std::string Output; |
| ASSERT_TRUE(runChecker(Code, Output)); |
| EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[1][2].val\n"); |
| } |
| |
| } // namespace |