xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp (revision e5dd70708596ae51455a0ffa086a00c5b29f8583)
1*e5dd7070Spatrick //=== CXXSelfAssignmentChecker.cpp -----------------------------*- C++ -*--===//
2*e5dd7070Spatrick //
3*e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e5dd7070Spatrick //
7*e5dd7070Spatrick //===----------------------------------------------------------------------===//
8*e5dd7070Spatrick //
9*e5dd7070Spatrick // This file defines CXXSelfAssignmentChecker, which tests all custom defined
10*e5dd7070Spatrick // copy and move assignment operators for the case of self assignment, thus
11*e5dd7070Spatrick // where the parameter refers to the same location where the this pointer
12*e5dd7070Spatrick // points to. The checker itself does not do any checks at all, but it
13*e5dd7070Spatrick // causes the analyzer to check every copy and move assignment operator twice:
14*e5dd7070Spatrick // once for when 'this' aliases with the parameter and once for when it may not.
15*e5dd7070Spatrick // It is the task of the other enabled checkers to find the bugs in these two
16*e5dd7070Spatrick // different cases.
17*e5dd7070Spatrick //
18*e5dd7070Spatrick //===----------------------------------------------------------------------===//
19*e5dd7070Spatrick 
20*e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
21*e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
22*e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23*e5dd7070Spatrick 
24*e5dd7070Spatrick using namespace clang;
25*e5dd7070Spatrick using namespace ento;
26*e5dd7070Spatrick 
27*e5dd7070Spatrick namespace {
28*e5dd7070Spatrick 
29*e5dd7070Spatrick class CXXSelfAssignmentChecker : public Checker<check::BeginFunction> {
30*e5dd7070Spatrick public:
31*e5dd7070Spatrick   CXXSelfAssignmentChecker();
32*e5dd7070Spatrick   void checkBeginFunction(CheckerContext &C) const;
33*e5dd7070Spatrick };
34*e5dd7070Spatrick }
35*e5dd7070Spatrick 
36*e5dd7070Spatrick CXXSelfAssignmentChecker::CXXSelfAssignmentChecker() {}
37*e5dd7070Spatrick 
38*e5dd7070Spatrick void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const {
39*e5dd7070Spatrick   if (!C.inTopFrame())
40*e5dd7070Spatrick     return;
41*e5dd7070Spatrick   const auto *LCtx = C.getLocationContext();
42*e5dd7070Spatrick   const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
43*e5dd7070Spatrick   if (!MD)
44*e5dd7070Spatrick     return;
45*e5dd7070Spatrick   if (!MD->isCopyAssignmentOperator() && !MD->isMoveAssignmentOperator())
46*e5dd7070Spatrick     return;
47*e5dd7070Spatrick   auto &State = C.getState();
48*e5dd7070Spatrick   auto &SVB = C.getSValBuilder();
49*e5dd7070Spatrick   auto ThisVal =
50*e5dd7070Spatrick       State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
51*e5dd7070Spatrick   auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), LCtx));
52*e5dd7070Spatrick   auto ParamVal = State->getSVal(Param);
53*e5dd7070Spatrick 
54*e5dd7070Spatrick   ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx);
55*e5dd7070Spatrick   const NoteTag *SelfAssignTag =
56*e5dd7070Spatrick     C.getNoteTag([MD](BugReport &BR) -> std::string {
57*e5dd7070Spatrick         SmallString<256> Msg;
58*e5dd7070Spatrick         llvm::raw_svector_ostream Out(Msg);
59*e5dd7070Spatrick         Out << "Assuming " << MD->getParamDecl(0)->getName() << " == *this";
60*e5dd7070Spatrick         return Out.str();
61*e5dd7070Spatrick       });
62*e5dd7070Spatrick   C.addTransition(SelfAssignState, SelfAssignTag);
63*e5dd7070Spatrick 
64*e5dd7070Spatrick   ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx);
65*e5dd7070Spatrick   const NoteTag *NonSelfAssignTag =
66*e5dd7070Spatrick     C.getNoteTag([MD](BugReport &BR) -> std::string {
67*e5dd7070Spatrick         SmallString<256> Msg;
68*e5dd7070Spatrick         llvm::raw_svector_ostream Out(Msg);
69*e5dd7070Spatrick         Out << "Assuming " << MD->getParamDecl(0)->getName() << " != *this";
70*e5dd7070Spatrick         return Out.str();
71*e5dd7070Spatrick       });
72*e5dd7070Spatrick   C.addTransition(NonSelfAssignState, NonSelfAssignTag);
73*e5dd7070Spatrick }
74*e5dd7070Spatrick 
75*e5dd7070Spatrick void ento::registerCXXSelfAssignmentChecker(CheckerManager &Mgr) {
76*e5dd7070Spatrick   Mgr.registerChecker<CXXSelfAssignmentChecker>();
77*e5dd7070Spatrick }
78*e5dd7070Spatrick 
79*e5dd7070Spatrick bool ento::shouldRegisterCXXSelfAssignmentChecker(const LangOptions &LO) {
80*e5dd7070Spatrick   return true;
81*e5dd7070Spatrick }
82