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

Reply via email to