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