1 //=== CXXSelfAssignmentChecker.cpp -----------------------------*- C++ -*--===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines CXXSelfAssignmentChecker, which tests all custom defined
10 // copy and move assignment operators for the case of self assignment, thus
11 // where the parameter refers to the same location where the this pointer
12 // points to. The checker itself does not do any checks at all, but it
13 // causes the analyzer to check every copy and move assignment operator twice:
14 // once for when 'this' aliases with the parameter and once for when it may not.
15 // It is the task of the other enabled checkers to find the bugs in these two
18 //===----------------------------------------------------------------------===//
20 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
21 #include "clang/StaticAnalyzer/Core/Checker.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24 using namespace clang
;
29 class CXXSelfAssignmentChecker
: public Checker
<check::BeginFunction
> {
31 CXXSelfAssignmentChecker();
32 void checkBeginFunction(CheckerContext
&C
) const;
36 CXXSelfAssignmentChecker::CXXSelfAssignmentChecker() {}
38 void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext
&C
) const {
41 const auto *LCtx
= C
.getLocationContext();
42 const auto *MD
= dyn_cast
<CXXMethodDecl
>(LCtx
->getDecl());
45 if (!MD
->isCopyAssignmentOperator() && !MD
->isMoveAssignmentOperator())
47 auto &State
= C
.getState();
48 auto &SVB
= C
.getSValBuilder();
50 State
->getSVal(SVB
.getCXXThis(MD
, LCtx
->getStackFrame()));
51 auto Param
= SVB
.makeLoc(State
->getRegion(MD
->getParamDecl(0), LCtx
));
52 auto ParamVal
= State
->getSVal(Param
);
54 ProgramStateRef SelfAssignState
= State
->bindLoc(Param
, ThisVal
, LCtx
);
55 const NoteTag
*SelfAssignTag
=
56 C
.getNoteTag([MD
](PathSensitiveBugReport
&BR
) -> std::string
{
58 llvm::raw_svector_ostream
Out(Msg
);
59 Out
<< "Assuming " << MD
->getParamDecl(0)->getName() << " == *this";
60 return std::string(Out
.str());
62 C
.addTransition(SelfAssignState
, SelfAssignTag
);
64 ProgramStateRef NonSelfAssignState
= State
->bindLoc(Param
, ParamVal
, LCtx
);
65 const NoteTag
*NonSelfAssignTag
=
66 C
.getNoteTag([MD
](PathSensitiveBugReport
&BR
) -> std::string
{
68 llvm::raw_svector_ostream
Out(Msg
);
69 Out
<< "Assuming " << MD
->getParamDecl(0)->getName() << " != *this";
70 return std::string(Out
.str());
72 C
.addTransition(NonSelfAssignState
, NonSelfAssignTag
);
75 void ento::registerCXXSelfAssignmentChecker(CheckerManager
&Mgr
) {
76 Mgr
.registerChecker
<CXXSelfAssignmentChecker
>();
79 bool ento::shouldRegisterCXXSelfAssignmentChecker(const CheckerManager
&mgr
) {