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