106f32e7eSjoerg //=== CXXSelfAssignmentChecker.cpp -----------------------------*- C++ -*--===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file defines CXXSelfAssignmentChecker, which tests all custom defined
1006f32e7eSjoerg // copy and move assignment operators for the case of self assignment, thus
1106f32e7eSjoerg // where the parameter refers to the same location where the this pointer
1206f32e7eSjoerg // points to. The checker itself does not do any checks at all, but it
1306f32e7eSjoerg // causes the analyzer to check every copy and move assignment operator twice:
1406f32e7eSjoerg // once for when 'this' aliases with the parameter and once for when it may not.
1506f32e7eSjoerg // It is the task of the other enabled checkers to find the bugs in these two
1606f32e7eSjoerg // different cases.
1706f32e7eSjoerg //
1806f32e7eSjoerg //===----------------------------------------------------------------------===//
1906f32e7eSjoerg 
2006f32e7eSjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
2106f32e7eSjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
2206f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2306f32e7eSjoerg 
2406f32e7eSjoerg using namespace clang;
2506f32e7eSjoerg using namespace ento;
2606f32e7eSjoerg 
2706f32e7eSjoerg namespace {
2806f32e7eSjoerg 
2906f32e7eSjoerg class CXXSelfAssignmentChecker : public Checker<check::BeginFunction> {
3006f32e7eSjoerg public:
3106f32e7eSjoerg   CXXSelfAssignmentChecker();
3206f32e7eSjoerg   void checkBeginFunction(CheckerContext &C) const;
3306f32e7eSjoerg };
3406f32e7eSjoerg }
3506f32e7eSjoerg 
CXXSelfAssignmentChecker()3606f32e7eSjoerg CXXSelfAssignmentChecker::CXXSelfAssignmentChecker() {}
3706f32e7eSjoerg 
checkBeginFunction(CheckerContext & C) const3806f32e7eSjoerg void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const {
3906f32e7eSjoerg   if (!C.inTopFrame())
4006f32e7eSjoerg     return;
4106f32e7eSjoerg   const auto *LCtx = C.getLocationContext();
4206f32e7eSjoerg   const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
4306f32e7eSjoerg   if (!MD)
4406f32e7eSjoerg     return;
4506f32e7eSjoerg   if (!MD->isCopyAssignmentOperator() && !MD->isMoveAssignmentOperator())
4606f32e7eSjoerg     return;
4706f32e7eSjoerg   auto &State = C.getState();
4806f32e7eSjoerg   auto &SVB = C.getSValBuilder();
4906f32e7eSjoerg   auto ThisVal =
5006f32e7eSjoerg       State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
5106f32e7eSjoerg   auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), LCtx));
5206f32e7eSjoerg   auto ParamVal = State->getSVal(Param);
5306f32e7eSjoerg 
5406f32e7eSjoerg   ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx);
5506f32e7eSjoerg   const NoteTag *SelfAssignTag =
56*13fbcb42Sjoerg     C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
5706f32e7eSjoerg         SmallString<256> Msg;
5806f32e7eSjoerg         llvm::raw_svector_ostream Out(Msg);
5906f32e7eSjoerg         Out << "Assuming " << MD->getParamDecl(0)->getName() << " == *this";
60*13fbcb42Sjoerg         return std::string(Out.str());
6106f32e7eSjoerg       });
6206f32e7eSjoerg   C.addTransition(SelfAssignState, SelfAssignTag);
6306f32e7eSjoerg 
6406f32e7eSjoerg   ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx);
6506f32e7eSjoerg   const NoteTag *NonSelfAssignTag =
66*13fbcb42Sjoerg     C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
6706f32e7eSjoerg         SmallString<256> Msg;
6806f32e7eSjoerg         llvm::raw_svector_ostream Out(Msg);
6906f32e7eSjoerg         Out << "Assuming " << MD->getParamDecl(0)->getName() << " != *this";
70*13fbcb42Sjoerg         return std::string(Out.str());
7106f32e7eSjoerg       });
7206f32e7eSjoerg   C.addTransition(NonSelfAssignState, NonSelfAssignTag);
7306f32e7eSjoerg }
7406f32e7eSjoerg 
registerCXXSelfAssignmentChecker(CheckerManager & Mgr)7506f32e7eSjoerg void ento::registerCXXSelfAssignmentChecker(CheckerManager &Mgr) {
7606f32e7eSjoerg   Mgr.registerChecker<CXXSelfAssignmentChecker>();
7706f32e7eSjoerg }
7806f32e7eSjoerg 
shouldRegisterCXXSelfAssignmentChecker(const CheckerManager & mgr)79*13fbcb42Sjoerg bool ento::shouldRegisterCXXSelfAssignmentChecker(const CheckerManager &mgr) {
8006f32e7eSjoerg   return true;
8106f32e7eSjoerg }
82