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