//===- 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 { 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(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", "Desc", "DocsURI"); }); } bool runChecker(StringRef Code, std::string &Output) { return runCheckerOnCode(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