xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //=== CXXSelfAssignmentChecker.cpp -----------------------------*- C++ -*--===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file defines CXXSelfAssignmentChecker, which tests all custom defined
107330f729Sjoerg // copy and move assignment operators for the case of self assignment, thus
117330f729Sjoerg // where the parameter refers to the same location where the this pointer
127330f729Sjoerg // points to. The checker itself does not do any checks at all, but it
137330f729Sjoerg // causes the analyzer to check every copy and move assignment operator twice:
147330f729Sjoerg // once for when 'this' aliases with the parameter and once for when it may not.
157330f729Sjoerg // It is the task of the other enabled checkers to find the bugs in these two
167330f729Sjoerg // different cases.
177330f729Sjoerg //
187330f729Sjoerg //===----------------------------------------------------------------------===//
197330f729Sjoerg 
207330f729Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
217330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
227330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
237330f729Sjoerg 
247330f729Sjoerg using namespace clang;
257330f729Sjoerg using namespace ento;
267330f729Sjoerg 
277330f729Sjoerg namespace {
287330f729Sjoerg 
297330f729Sjoerg class CXXSelfAssignmentChecker : public Checker<check::BeginFunction> {
307330f729Sjoerg public:
317330f729Sjoerg   CXXSelfAssignmentChecker();
327330f729Sjoerg   void checkBeginFunction(CheckerContext &C) const;
337330f729Sjoerg };
347330f729Sjoerg }
357330f729Sjoerg 
CXXSelfAssignmentChecker()367330f729Sjoerg CXXSelfAssignmentChecker::CXXSelfAssignmentChecker() {}
377330f729Sjoerg 
checkBeginFunction(CheckerContext & C) const387330f729Sjoerg void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const {
397330f729Sjoerg   if (!C.inTopFrame())
407330f729Sjoerg     return;
417330f729Sjoerg   const auto *LCtx = C.getLocationContext();
427330f729Sjoerg   const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
437330f729Sjoerg   if (!MD)
447330f729Sjoerg     return;
457330f729Sjoerg   if (!MD->isCopyAssignmentOperator() && !MD->isMoveAssignmentOperator())
467330f729Sjoerg     return;
477330f729Sjoerg   auto &State = C.getState();
487330f729Sjoerg   auto &SVB = C.getSValBuilder();
497330f729Sjoerg   auto ThisVal =
507330f729Sjoerg       State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
517330f729Sjoerg   auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), LCtx));
527330f729Sjoerg   auto ParamVal = State->getSVal(Param);
537330f729Sjoerg 
547330f729Sjoerg   ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx);
557330f729Sjoerg   const NoteTag *SelfAssignTag =
56*e038c9c4Sjoerg     C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
577330f729Sjoerg         SmallString<256> Msg;
587330f729Sjoerg         llvm::raw_svector_ostream Out(Msg);
597330f729Sjoerg         Out << "Assuming " << MD->getParamDecl(0)->getName() << " == *this";
60*e038c9c4Sjoerg         return std::string(Out.str());
617330f729Sjoerg       });
627330f729Sjoerg   C.addTransition(SelfAssignState, SelfAssignTag);
637330f729Sjoerg 
647330f729Sjoerg   ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx);
657330f729Sjoerg   const NoteTag *NonSelfAssignTag =
66*e038c9c4Sjoerg     C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
677330f729Sjoerg         SmallString<256> Msg;
687330f729Sjoerg         llvm::raw_svector_ostream Out(Msg);
697330f729Sjoerg         Out << "Assuming " << MD->getParamDecl(0)->getName() << " != *this";
70*e038c9c4Sjoerg         return std::string(Out.str());
717330f729Sjoerg       });
727330f729Sjoerg   C.addTransition(NonSelfAssignState, NonSelfAssignTag);
737330f729Sjoerg }
747330f729Sjoerg 
registerCXXSelfAssignmentChecker(CheckerManager & Mgr)757330f729Sjoerg void ento::registerCXXSelfAssignmentChecker(CheckerManager &Mgr) {
767330f729Sjoerg   Mgr.registerChecker<CXXSelfAssignmentChecker>();
777330f729Sjoerg }
787330f729Sjoerg 
shouldRegisterCXXSelfAssignmentChecker(const CheckerManager & mgr)79*e038c9c4Sjoerg bool ento::shouldRegisterCXXSelfAssignmentChecker(const CheckerManager &mgr) {
807330f729Sjoerg   return true;
817330f729Sjoerg }
82