1 //===----------------------------------------------------------------------===// 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 "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 10 #include "CheckerRegistration.h" 11 #include "clang/Basic/LLVM.h" 12 #include "clang/Frontend/CompilerInstance.h" 13 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 14 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 15 #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" 16 #include "clang/StaticAnalyzer/Core/Checker.h" 17 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 20 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" 21 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" 22 #include "clang/Tooling/Tooling.h" 23 #include "gtest/gtest.h" 24 25 namespace clang { 26 namespace ento { 27 namespace { 28 29 void reportBug(const CheckerBase *Checker, const CallEvent &Call, 30 CheckerContext &C, StringRef WarningMsg) { 31 C.getBugReporter().EmitBasicReport( 32 nullptr, Checker, "", categories::LogicError, WarningMsg, 33 PathDiagnosticLocation(Call.getOriginExpr(), C.getSourceManager(), 34 C.getLocationContext()), 35 {}); 36 } 37 38 class CXXDeallocatorChecker : public Checker<check::PreCall> { 39 std::unique_ptr<BugType> BT_uninitField; 40 41 public: 42 CXXDeallocatorChecker() 43 : BT_uninitField(new BugType(this, "CXXDeallocator")) {} 44 45 void checkPreCall(const CallEvent &Call, CheckerContext &C) const { 46 const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call); 47 if (!DC) { 48 return; 49 } 50 51 SmallString<100> WarningBuf; 52 llvm::raw_svector_ostream WarningOS(WarningBuf); 53 WarningOS << "NumArgs: " << DC->getNumArgs(); 54 55 reportBug(this, *DC, C, WarningBuf); 56 } 57 }; 58 59 void addCXXDeallocatorChecker(AnalysisASTConsumer &AnalysisConsumer, 60 AnalyzerOptions &AnOpts) { 61 AnOpts.CheckersAndPackages = {{"test.CXXDeallocator", true}}; 62 AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { 63 Registry.addChecker<CXXDeallocatorChecker>("test.CXXDeallocator", 64 "Description", ""); 65 }); 66 } 67 68 // TODO: What we should really be testing here is all the different varieties 69 // of delete operators, and wether the retrieval of their arguments works as 70 // intended. At the time of writing this file, CXXDeallocatorCall doesn't pick 71 // up on much of those due to the AST not containing CXXDeleteExpr for most of 72 // the standard/custom deletes. 73 TEST(CXXDeallocatorCall, SimpleDestructor) { 74 std::string Diags; 75 EXPECT_TRUE(runCheckerOnCode<addCXXDeallocatorChecker>(R"( 76 struct A {}; 77 78 void f() { 79 A *a = new A; 80 delete a; 81 } 82 )", 83 Diags)); 84 EXPECT_EQ(Diags, "test.CXXDeallocator: NumArgs: 1\n"); 85 } 86 87 } // namespace 88 } // namespace ento 89 } // namespace clang 90