[cfe-commits] r48867 - in /cfe/trunk: include/clang/Analysis/PathSensitive/AnnotatedPath.h include/clang/Analysis/PathSensitive/GRAuditor.h include/clang/Analysis/PathSensitive/GRCoreEngine.h include/clang/Analysis/PathSensitive/GRExprEngine.h include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h lib/Analysis/BasicObjCFoundationChecks.cpp lib/Analysis/GRExprEngine.cpp

Ted Kremenek kremenek at apple.com
Thu Mar 27 00:25:52 PDT 2008


Author: kremenek
Date: Thu Mar 27 02:25:52 2008
New Revision: 48867

URL: http://llvm.org/viewvc/llvm-project?rev=48867&view=rev
Log:
Added "GRAuditor" and "GRSimpleAPICheck" interface to allow simple stateless checkers to be injected into the analyzer.
Added "AnnotatedPath" class to record an annotated path that will be useful for inspecting paths.
Added some boilerplate code for simple checks of Apple's Foundation API.

Added:
    cfe/trunk/include/clang/Analysis/PathSensitive/AnnotatedPath.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRAuditor.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
    cfe/trunk/lib/Analysis/BasicObjCFoundationChecks.cpp
Modified:
    cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
    cfe/trunk/lib/Analysis/GRExprEngine.cpp

Added: cfe/trunk/include/clang/Analysis/PathSensitive/AnnotatedPath.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/AnnotatedPath.h?rev=48867&view=auto

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/AnnotatedPath.h (added)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/AnnotatedPath.h Thu Mar 27 02:25:52 2008
@@ -0,0 +1,65 @@
+//=-- AnnotatedPath.h - An annotated list of ExplodedNodes -*- 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 AnnotatedPath, which represents a collection of
+//  annotated ExplodedNodes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANNOTPATH
+#define LLVM_CLANG_ANALYSIS_ANNOTPATH
+
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include <string>
+#include <list>
+
+namespace clang {
+
+  class Expr;
+
+template <typename STATE>
+class AnnotatedNode {
+  ExplodedNode<STATE> *Node;
+  std::string annotation;
+  Expr* E;
+
+public:
+  AnnotatedNode(ExplodedNode<STATE>* N, const std::string& annot,
+                Expr* e = NULL)
+  : Node(N), annotation(annot), E(e) {}
+
+  ExplodedNode<STATE> getNode() const { return Node; }
+  
+  const std::string& getString() const { return annotation; }
+  
+  Expr* getExpr() const { return E; }
+};
+  
+
+template <typename STATE>
+class AnnotatedPath {
+  typedef std::list<AnnotatedNode<STATE> >  impl;
+  impl path;
+public:
+  AnnotatedPath();
+  
+  void push_back(ExplodedNode<STATE>* N, const std::string& s, Expr* E = NULL) {
+    path.push_back(AnnotatedNode<STATE>(N, s, E));
+  }
+  
+  typedef typename impl::iterator iterator;
+  
+  iterator begin() { return path.begin(); }
+  iterator end() { return path.end(); }
+  
+};
+  
+} // end clang namespace
+
+#endif

Added: cfe/trunk/include/clang/Analysis/PathSensitive/GRAuditor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRAuditor.h?rev=48867&view=auto

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRAuditor.h (added)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRAuditor.h Thu Mar 27 02:25:52 2008
@@ -0,0 +1,38 @@
+//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- 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 GRAuditor and its primary subclasses, an interface
+//  to audit the creation of ExplodedNodes.  This interface can be used
+//  to implement simple checkers that do not mutate analysis state but
+//  instead operate by perfoming simple logical checks at key monitoring
+//  locations (e.g., function calls).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR
+#define LLVM_CLANG_ANALYSIS_GRAUDITOR
+
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+
+namespace clang {
+  
+template <typename STATE>
+class GRAuditor {
+public:
+  typedef ExplodedNode<STATE>   NodeTy;
+  
+  virtual ~GRAuditor() {}
+  virtual bool Audit(NodeTy* N) = 0;
+};
+  
+  
+} // end clang namespace
+
+#endif

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h?rev=48867&r1=48866&r2=48867&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h Thu Mar 27 02:25:52 2008
@@ -15,7 +15,7 @@
 #ifndef LLVM_CLANG_ANALYSIS_GRENGINE
 #define LLVM_CLANG_ANALYSIS_GRENGINE
 
-#include "clang/AST/Stmt.h"
+#include "clang/AST/Expr.h"
 #include "clang/Analysis/PathSensitive/ExplodedGraph.h"
 #include "clang/Analysis/PathSensitive/GRWorkList.h"
 #include "clang/Analysis/PathSensitive/GRBlockCounter.h"
@@ -163,6 +163,16 @@
   CFGBlock* getBlock() const { return &B; }
 };
 
+template <typename STATE>
+class GRNodeAuditor {
+public:
+  typedef ExplodedNode<STATE>   NodeTy;
+  
+  virtual ~GRNodeAuditor() {}
+  virtual bool Audit(NodeTy* N) = 0;
+};
+  
+  
 template<typename STATE>
 class GRStmtNodeBuilder  {
   typedef STATE                   StateTy;
@@ -171,10 +181,28 @@
   GRStmtNodeBuilderImpl& NB;
   StateTy* CleanedState;
   
+  GRNodeAuditor<StateTy> **CallExprAuditBeg, **CallExprAuditEnd;
+  GRNodeAuditor<StateTy> **ObjCMsgExprAuditBeg, **ObjCMsgExprAuditEnd;
+  
 public:
-  GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb) : NB(nb), BuildSinks(false) {
+  GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb) : NB(nb),
+    CallExprAuditBeg(0), CallExprAuditEnd(0),
+    ObjCMsgExprAuditBeg(0), ObjCMsgExprAuditEnd(0),  BuildSinks(false) {
+      
     CleanedState = getLastNode()->getState();
   }
+  
+  void setObjCMsgExprAuditors(GRNodeAuditor<StateTy> **B,
+                              GRNodeAuditor<StateTy> **E) {
+    ObjCMsgExprAuditBeg = B;
+    ObjCMsgExprAuditEnd = E;
+  }
+  
+  void setCallExprAuditors(GRNodeAuditor<StateTy> **B,
+                           GRNodeAuditor<StateTy> **E) {
+    CallExprAuditBeg = B;
+    CallExprAuditEnd = E;
+  }  
     
   NodeTy* getLastNode() const {
     return static_cast<NodeTy*>(NB.getLastNode());
@@ -223,8 +251,18 @@
     if (N) {      
       if (BuildSinks)
         N->markAsSink();
-      else
+      else {
         Dst.Add(N);
+        
+        if (isa<CallExpr>(S))
+          for (GRNodeAuditor<StateTy>** I = CallExprAuditBeg;
+               I != CallExprAuditEnd; ++I)
+            (*I)->Audit(N);
+        else if (isa<ObjCMessageExpr>(S))
+          for (GRNodeAuditor<StateTy>** I = ObjCMsgExprAuditBeg;
+               I != ObjCMsgExprAuditEnd; ++I)
+            (*I)->Audit(N);
+      }
     }
     
     return N;

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=48867&r1=48866&r2=48867&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Thu Mar 27 02:25:52 2008
@@ -15,10 +15,13 @@
 
 #include "clang/Analysis/PathSensitive/GRCoreEngine.h"
 #include "clang/Analysis/PathSensitive/ValueState.h"
+#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
 #include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
 
 namespace clang {
   
+  class StatelessChecks;
+  
 class GRExprEngine {
   
 public:
@@ -32,6 +35,7 @@
   typedef GRIndirectGotoNodeBuilder<GRExprEngine>  IndirectGotoNodeBuilder;
   typedef GRSwitchNodeBuilder<GRExprEngine>        SwitchNodeBuilder;
   typedef ExplodedNodeSet<StateTy>                 NodeSet;
+  
     
 protected:
   /// G - the simulation graph.
@@ -67,6 +71,12 @@
   
   /// CurrentStmt - The current block-level statement.
   Stmt* CurrentStmt;
+  
+  typedef llvm::SmallVector<GRSimpleAPICheck*,2> SimpleChecksTy;
+  
+  SimpleChecksTy CallChecks;
+  SimpleChecksTy MsgExprChecks;
+  
 
   typedef llvm::SmallPtrSet<NodeTy*,2> UndefBranchesTy;  
   typedef llvm::SmallPtrSet<NodeTy*,2> UndefStoresTy;
@@ -278,6 +288,26 @@
     return UndefReceivers.end();
   }
   
+  typedef SimpleChecksTy::iterator simple_checks_iterator;
+  
+  simple_checks_iterator call_auditors_begin() { return CallChecks.begin(); }
+  simple_checks_iterator call_auditors_end() { return CallChecks.end(); }
+  
+  simple_checks_iterator msgexpr_auditors_begin() {
+    return MsgExprChecks.begin();
+  }
+  simple_checks_iterator msgexpr_auditors_end() {
+    return MsgExprChecks.end();
+  }
+  
+  void AddCallCheck(GRSimpleAPICheck* A) {
+    CallChecks.push_back(A);
+  }
+  
+  void AddObjCMessageExprCheck(GRSimpleAPICheck* A) {
+    MsgExprChecks.push_back(A);
+  }
+  
   /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
   ///  nodes by processing the 'effects' of a block-level statement.  
   void ProcessStmt(Stmt* S, StmtNodeBuilder& builder);    

Added: cfe/trunk/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h?rev=48867&view=auto

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h (added)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h Thu Mar 27 02:25:52 2008
@@ -0,0 +1,35 @@
+// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- 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 the interface for building simple, path-sensitive checks
+//  that are stateless and only emit warnings at errors that occur at
+//  CallExpr or ObjCMessageExpr.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS
+#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
+
+#include "clang/Analysis/PathSensitive/GRAuditor.h"
+
+namespace clang {
+  
+class ValueState;
+  
+class GRSimpleAPICheck : public GRAuditor<ValueState> {
+public:
+  GRSimpleAPICheck() {}
+  virtual ~GRSimpleAPICheck() {}
+
+
+};
+
+} // end namespace clang
+
+#endif

Added: cfe/trunk/lib/Analysis/BasicObjCFoundationChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BasicObjCFoundationChecks.cpp?rev=48867&view=auto

==============================================================================
--- cfe/trunk/lib/Analysis/BasicObjCFoundationChecks.cpp (added)
+++ cfe/trunk/lib/Analysis/BasicObjCFoundationChecks.cpp Thu Mar 27 02:25:52 2008
@@ -0,0 +1,139 @@
+//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- 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 BasicObjCFoundationChecks, a class that encapsulates
+//  a set of simple checks to run on Objective-C code using Apple's Foundation
+//  classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Analysis/PathSensitive/ValueState.h"
+#include "clang/Analysis/PathSensitive/AnnotatedPath.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/Compiler.h"
+
+#include <vector>
+
+using namespace clang;
+  
+namespace {
+  
+class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
+
+ ASTContext &Ctx;
+ ValueStateManager* VMgr;
+ std::list<AnnotatedPath<ValueState> > Errors;
+      
+ RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
+      
+ bool isNSString(ObjCInterfaceType* T, const char* suffix);
+ bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
+      
+ void RegisterError(NodeTy* N, Expr* E, const char *msg);
+
+public:
+  BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr) 
+    : Ctx(ctx), VMgr(vmgr) {}
+      
+  virtual ~BasicObjCFoundationChecks() {}
+  
+  virtual bool Audit(ExplodedNode<ValueState>* N);
+};
+  
+} // end anonymous namespace
+
+
+bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {
+  
+  ObjCMessageExpr* ME =
+    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+  
+  Expr* Receiver = ME->getReceiver();
+  
+  if (!Receiver)
+    return false;
+  
+  assert (Receiver->getType()->isPointerType());
+
+  const PointerType* T = Receiver->getType()->getAsPointerType();
+
+  ObjCInterfaceType* ReceiverType =
+    dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
+  
+  if (!ReceiverType)
+    return false;
+  
+  const char* name = ReceiverType->getDecl()->getIdentifier()->getName();  
+
+  if (name[0] != 'N' || name[1] != 'S')
+    return false;
+      
+  name += 2;
+  
+  // FIXME: Make all of this faster.
+  
+  if (isNSString(ReceiverType, name))
+    return AuditNSString(N, ME);
+
+  return false;  
+}
+
+//===----------------------------------------------------------------------===//
+// Error reporting.
+//===----------------------------------------------------------------------===//
+
+
+void BasicObjCFoundationChecks::RegisterError(NodeTy* N,
+                                              Expr* E, const char *msg) {
+  
+  Errors.push_back(AnnotatedPath<ValueState>());
+  Errors.back().push_back(N, msg, E);
+}
+
+//===----------------------------------------------------------------------===//
+// NSString checking.
+//===----------------------------------------------------------------------===//
+
+bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
+                                           const char* suffix) {
+  
+  return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
+}
+
+bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N, 
+                                              ObjCMessageExpr* ME) {
+  
+  Selector S = ME->getSelector();
+  
+  if (S.isUnarySelector())
+    return false;
+
+  // FIXME: This is going to be really slow doing these checks with
+  //  lexical comparisons.
+  
+  std::string name = S.getName();
+  ValueState* St = N->getState();
+  
+  if (name == "compare:") {
+    // Check if the compared NSString is nil.
+    Expr * E = ME->getArg(0);
+    RVal X = GetRVal(St, E);
+    
+    if (isa<lval::ConcreteInt>(X)) {
+      RegisterError(N, E,
+                    "Argument to NSString method 'compare:' cannot be nil.");
+    }
+  }
+  
+  return false;
+}

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=48867&r1=48866&r2=48867&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Thu Mar 27 02:25:52 2008
@@ -407,6 +407,19 @@
   CurrentStmt = S;
   NodeSet Dst;
   
+  // Set up our simple checks.
+  
+  if (!MsgExprChecks.empty())
+    Builder->setObjCMsgExprAuditors(
+      (GRNodeAuditor<ValueState>**) &MsgExprChecks[0],
+      (GRNodeAuditor<ValueState>**) (&MsgExprChecks[0] + MsgExprChecks.size()));
+
+  
+  if (!CallChecks.empty())
+    Builder->setCallExprAuditors(
+      (GRNodeAuditor<ValueState>**) &CallChecks[0],
+      (GRNodeAuditor<ValueState>**) (&CallChecks[0] + CallChecks.size()));
+  
   // Create the cleaned state.
 
   CleanedState = StateMgr.RemoveDeadBindings(StmtEntryNode->getState(),





More information about the cfe-commits mailing list