baloghadamsoftware updated this revision to Diff 54968. baloghadamsoftware added a comment.
Initial comments added to the checker and tests are converted from <CR><LF> (DOS) to <LF> (Unix) format. http://reviews.llvm.org/D19311 Files: lib/StaticAnalyzer/Checkers/CMakeLists.txt lib/StaticAnalyzer/Checkers/Checkers.td lib/StaticAnalyzer/Checkers/SelfAssignmentChecker.cpp lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp test/Analysis/self-assign-unused.cpp test/Analysis/self-assign-used.cpp
Index: test/Analysis/self-assign-used.cpp =================================================================== --- /dev/null +++ test/Analysis/self-assign-used.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus,unix.Malloc,debug.ExprInspection %s -verify + +extern "C" char *strdup(const char* s); +extern "C" void free(void* ptr); + +class String { +public: + String(const char *s = "") : str(strdup(s)) {} + String(const String &rhs) : str(strdup(rhs.str)) {} + ~String(); + String& operator=(const String &rhs); + operator const char*() const; +private: + char *str; +}; + +String::~String() { + free(str); +} + +String& String::operator=(const String &rhs) { + free(str); + str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} + return *this; +} + +String::operator const char*() const { + return str; +} + +int main() { + String s1 ("test"), s2; + s2 = s1; + return 0; +} Index: test/Analysis/self-assign-unused.cpp =================================================================== --- /dev/null +++ test/Analysis/self-assign-unused.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus,unix.Malloc,debug.ExprInspection %s -verify + +extern "C" char *strdup(const char* s); +extern "C" void free(void* ptr); + +class String { +public: + String(const char *s = "") : str(strdup(s)) {} + String(const String &rhs) : str(strdup(rhs.str)) {} + ~String(); + String& operator=(const String &rhs); + operator const char*() const; +private: + char *str; +}; + +String::~String() { + free(str); +} + +String& String::operator=(const String &rhs) { + free(str); + str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} + return *this; +} + +String::operator const char*() const { + return str; +} + +int main() { + return 0; +} Index: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp =================================================================== --- lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -432,6 +432,10 @@ // Count naming convention errors more aggressively. if (isa<ObjCMethodDecl>(D)) return false; + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if(MD->isCopyAssignmentOperator()||MD->isMoveAssignmentOperator()) + return false; + } // Otherwise, if we visited the function before, do not reanalyze it. return Visited.count(D); @@ -443,9 +447,7 @@ // We want to reanalyze all ObjC methods as top level to report Retain // Count naming convention errors more aggressively. But we should tune down // inlining when reanalyzing an already inlined function. - if (Visited.count(D)) { - assert(isa<ObjCMethodDecl>(D) && - "We are only reanalyzing ObjCMethods."); + if (Visited.count(D)&&isa<ObjCMethodDecl>(D)) { const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D); if (ObjCM->getMethodFamily() != OMF_init) return ExprEngine::Inline_Minimal; Index: lib/StaticAnalyzer/Checkers/SelfAssignmentChecker.cpp =================================================================== --- /dev/null +++ lib/StaticAnalyzer/Checkers/SelfAssignmentChecker.cpp @@ -0,0 +1,58 @@ +//=== SelfAssignmentChecker.cpp --------------------------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SelfAssignmentChecker, which checks all custom defined +// copy and move assignment operators for the case of self assignment, thus +// where the parameter refers to the same location where the this pointer +// points to. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + +using namespace clang; +using namespace ento; + +namespace { + +class SelfAssignmentChecker : public Checker<check::BeginFunction> { +public: + SelfAssignmentChecker(); + void checkBeginFunction(CheckerContext &C) const; +}; +} + +SelfAssignmentChecker::SelfAssignmentChecker() {} + +void SelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const { + if (!C.inTopFrame()) + return; + const auto *LCtx = C.getLocationContext(); + const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl()); + if (!MD) + return; + if (!MD->isCopyAssignmentOperator() && !MD->isMoveAssignmentOperator()) + return; + auto &State = C.getState(); + auto &SVB = C.getSValBuilder(); + auto ThisVal = + State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame())); + auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), LCtx)); + auto ParamVal = State->getSVal(Param); + ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal); + C.addTransition(SelfAssignState); + ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal); + C.addTransition(NonSelfAssignState); +} + +void ento::registerSelfAssignmentChecker(CheckerManager &Mgr) { + Mgr.registerChecker<SelfAssignmentChecker>(); +} Index: lib/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- lib/StaticAnalyzer/Checkers/Checkers.td +++ lib/StaticAnalyzer/Checkers/Checkers.td @@ -245,6 +245,10 @@ HelpText<"Check for memory leaks. Traces memory managed by new/delete.">, DescFile<"MallocChecker.cpp">; +def SelfAssignmentChecker : Checker<"SelfAssignment">, + HelpText<"Checks copy and move assignment operators for self assignment">, + DescFile<"SelfAssignmentChecker.cpp">; + } // end: "cplusplus" let ParentPackage = CplusplusAlpha in { Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt =================================================================== --- lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -65,6 +65,7 @@ RetainCountChecker.cpp ReturnPointerRangeChecker.cpp ReturnUndefChecker.cpp + SelfAssignmentChecker.cpp SimpleStreamChecker.cpp StackAddrEscapeChecker.cpp StreamChecker.cpp
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits