[cfe-commits] r96147 - in /cfe/trunk: include/clang/Checker/Checkers/LocalCheckers.h include/clang/Driver/CC1Options.td include/clang/Frontend/Analyses.def lib/Checker/CMakeLists.txt lib/Checker/LLVMConventionsChecker.cpp lib/Frontend/AnalysisConsumer.cpp

Ted Kremenek kremenek at apple.com
Sat Feb 13 18:45:18 PST 2010


Author: kremenek
Date: Sat Feb 13 20:45:18 2010
New Revision: 96147

URL: http://llvm.org/viewvc/llvm-project?rev=96147&view=rev
Log:
Add new static analyzer for checking LLVM coding conventions: -analyzer-check-llvm-conventions

Currently these checks are intended to be largely syntactical, but may get more
sophisticated over time.

As an initial foray into this brave new world, emit a static analyzer warning
when binding a temporary 'std::string' to an 'llvm::StringRef' where the
lifetime of the 'std::string' does not outlive the 'llvm::StringRef'.

Added:
    cfe/trunk/lib/Checker/LLVMConventionsChecker.cpp
Modified:
    cfe/trunk/include/clang/Checker/Checkers/LocalCheckers.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Frontend/Analyses.def
    cfe/trunk/lib/Checker/CMakeLists.txt
    cfe/trunk/lib/Frontend/AnalysisConsumer.cpp

Modified: cfe/trunk/include/clang/Checker/Checkers/LocalCheckers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/Checkers/LocalCheckers.h?rev=96147&r1=96146&r2=96147&view=diff

==============================================================================
--- cfe/trunk/include/clang/Checker/Checkers/LocalCheckers.h (original)
+++ cfe/trunk/include/clang/Checker/Checkers/LocalCheckers.h Sat Feb 13 20:45:18 2010
@@ -50,8 +50,8 @@
 void RegisterExperimentalChecks(GRExprEngine &Eng);
 void RegisterExperimentalInternalChecks(GRExprEngine &Eng);
 
+void CheckLLVMConventions(const Decl *D, BugReporter &BR);
 void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR);
-
 void CheckSizeofPointer(const Decl *D, BugReporter &BR);
 
 void RegisterCallInliner(GRExprEngine &Eng);

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=96147&r1=96146&r2=96147&view=diff

==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Sat Feb 13 20:45:18 2010
@@ -38,6 +38,8 @@
   HelpText<"View Control-Flow Graphs using GraphViz">;
 def analysis_DisplayLiveVariables : Flag<"-dump-live-variables">,
   HelpText<"Print results of live variable analysis">;
+def analysis_LLVMConventionChecker : Flag<"-analyzer-check-llvm-conventions">,
+  HelpText<"Check code for LLVM codebase conventions (domain-specific)">;
 def analysis_SecuritySyntacticChecks : Flag<"-analyzer-check-security-syntactic">,
   HelpText<"Perform quick security checks that require no data flow">;
 def analysis_WarnDeadStores : Flag<"-analyzer-check-dead-stores">,

Modified: cfe/trunk/include/clang/Frontend/Analyses.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/Analyses.def?rev=96147&r1=96146&r2=96147&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/Analyses.def (original)
+++ cfe/trunk/include/clang/Frontend/Analyses.def Sat Feb 13 20:45:18 2010
@@ -28,6 +28,10 @@
          "Perform quick security checks that require no data flow",
          Code)
 
+ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions",
+  "Check code for LLVM codebase conventions (domain-specific)",
+  Code)
+
 ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores",
          "Warn about stores to dead variables", Code)
 

Modified: cfe/trunk/lib/Checker/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CMakeLists.txt?rev=96147&r1=96146&r2=96147&view=diff

==============================================================================
--- cfe/trunk/lib/Checker/CMakeLists.txt (original)
+++ cfe/trunk/lib/Checker/CMakeLists.txt Sat Feb 13 20:45:18 2010
@@ -34,6 +34,7 @@
   GRExprEngine.cpp
   GRExprEngineExperimentalChecks.cpp
   GRState.cpp
+  LLVMConventionsChecker.cpp
   MallocChecker.cpp
   ManagerRegistry.cpp
   MemRegion.cpp

Added: cfe/trunk/lib/Checker/LLVMConventionsChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/LLVMConventionsChecker.cpp?rev=96147&view=auto

==============================================================================
--- cfe/trunk/lib/Checker/LLVMConventionsChecker.cpp (added)
+++ cfe/trunk/lib/Checker/LLVMConventionsChecker.cpp Sat Feb 13 20:45:18 2010
@@ -0,0 +1,127 @@
+//=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*-
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines LLVMConventionsChecker, a bunch of small little checks
+// for checking specific coding conventions in the LLVM/Clang codebase.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include <string>
+#include <llvm/ADT/StringRef.h>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Check if an llvm::StringRef is bound to temporary std::string whose lifetime
+// is shorter than the StringRef's.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
+  BugReporter &BR;
+public:
+  StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
+  void VisitChildren(Stmt *S) {
+    for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
+      I != E; ++I)
+      if (Stmt *child = *I)
+        Visit(child);
+  }
+  void VisitStmt(Stmt *S) { VisitChildren(S); }
+  void VisitDeclStmt(DeclStmt *DS);
+private:
+  void VisitVarDecl(VarDecl *VD);
+};
+} // end anonymous namespace
+
+static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
+  StringRefCheckerVisitor walker(BR);
+  walker.Visit(D->getBody());
+}
+
+void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
+  for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
+    if (VarDecl *VD = dyn_cast<VarDecl>(*I))
+      VisitVarDecl(VD);
+}
+
+static bool IsStringRef(QualType T) {
+  const RecordType *RT = T->getAs<RecordType>();
+  if (!RT)
+    return false;
+  
+  return llvm::StringRef(QualType(RT, 0).getAsString()) ==
+         "class llvm::StringRef";
+}
+
+static bool IsStdString(QualType T) {
+  if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>())
+    T = QT->getNamedType();
+  
+  const TypedefType *TT = T->getAs<TypedefType>();
+  if (!TT)
+    return false;
+    
+  const TypedefDecl *TD = TT->getDecl();    
+  const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(TD->getDeclContext());
+  if (!ND)
+    return false;
+  const IdentifierInfo *II = ND->getIdentifier();
+  if (!II || II->getName() != "std")
+    return false;
+
+  DeclarationName N = TD->getDeclName();
+  return llvm::StringRef(N.getAsString()) == "string";
+}
+
+void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
+  Expr *Init = VD->getInit();
+  if (!Init)
+    return; 
+    
+  // Pattern match for:
+  // llvm::StringRef x = call() (where call returns std::string)
+  if (!IsStringRef(VD->getType()))
+    return;
+  CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init);
+  if (!Ex1)
+    return;
+  CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
+  if (!Ex2 || Ex2->getNumArgs() != 1)
+    return;
+  ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
+  if (!Ex3)
+    return;
+  CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
+  if (!Ex4 || Ex4->getNumArgs() != 1)
+    return;
+  ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
+  if (!Ex5)
+    return;
+  CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
+  if (!Ex6 || !IsStdString(Ex6->getType()))
+    return;
+  
+  // Okay, badness!  Report an error.
+  BR.EmitBasicReport("StringRef should not be bound to temporary "
+                     "std::string that it outlives", "LLVM Conventions",
+                     VD->getLocStart(), Init->getSourceRange());
+}
+
+//===----------------------------------------------------------------------===//
+// Entry point for all checks.
+//===----------------------------------------------------------------------===//
+
+void clang::CheckLLVMConventions(const Decl *D, BugReporter &BR) {
+  CheckStringRefAssignedTemporary(D, BR);
+}

Modified: cfe/trunk/lib/Frontend/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/AnalysisConsumer.cpp?rev=96147&r1=96146&r2=96147&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/AnalysisConsumer.cpp (original)
+++ cfe/trunk/lib/Frontend/AnalysisConsumer.cpp Sat Feb 13 20:45:18 2010
@@ -446,6 +446,14 @@
   CheckSecuritySyntaxOnly(D, BR);
 }
 
+static void ActionLLVMConventionChecker(AnalysisConsumer &C,
+                                        AnalysisManager &mgr,
+                                        Decl *D) {
+  C.DisplayFunction(D);
+  BugReporter BR(mgr);
+  CheckLLVMConventions(D, BR);
+}
+
 static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
                                   Decl *D) {
   if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)





More information about the cfe-commits mailing list