]> granicus.if.org Git - clang/commitdiff
Added path-sensitive check for return statements that return the address
authorTed Kremenek <kremenek@apple.com>
Mon, 31 Mar 2008 15:02:58 +0000 (15:02 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 31 Mar 2008 15:02:58 +0000 (15:02 +0000)
of a stack variable.  This is the path-sensitive version of a check that
is already done during semantic analysis.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@48980 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/PathSensitive/GRExprEngine.h
lib/Analysis/GRExprEngine.cpp
lib/Analysis/GRSimpleVals.cpp
test/Analysis/stack-addr-ps.c [new file with mode: 0644]

index b04469efc3601d2dc8df2ed913daeaa5f93ccd4c..f286816f382cd94899e6dba4826fa4857b6f5735 100644 (file)
@@ -86,8 +86,12 @@ protected:
   typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy;
   typedef llvm::SmallPtrSet<NodeTy*,2> BadDividesTy;
   typedef llvm::SmallPtrSet<NodeTy*,2> NoReturnCallsTy;  
-  typedef llvm::SmallPtrSet<NodeTy*,2> UndefResultsTy;  
+  typedef llvm::SmallPtrSet<NodeTy*,2> UndefResultsTy;
+  typedef llvm::SmallPtrSet<NodeTy*,2> RetsStackAddrTy;
 
+  /// RetsStackAddr - Nodes in the ExplodedGraph that result from returning
+  ///  the address of a stack variable.
+  RetsStackAddrTy RetsStackAddr;
   
   /// UndefBranches - Nodes in the ExplodedGraph that result from
   ///  taking a branch based on an undefined value.
@@ -179,6 +183,10 @@ public:
   ///  in the ExplodedGraph.
   ValueState* getInitialState();
   
+  bool isRetStackAddr(const NodeTy* N) const {
+    return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0;
+  }
+  
   bool isUndefControlFlow(const NodeTy* N) const {
     return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0;
   }
@@ -229,6 +237,10 @@ public:
     return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0;
   }
   
+  typedef RetsStackAddrTy::iterator ret_stackaddr_iterator;
+  ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); }
+  ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); }  
+  
   typedef UndefBranchesTy::iterator undef_branch_iterator;
   undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); }
   undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }  
@@ -476,6 +488,9 @@ protected:
   /// VisitLogicalExpr - Transfer function logic for '&&', '||'
   void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
   
+  /// VisitReturnStmt - Transfer function logic for return statements.
+  void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst);
+  
   /// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type).
   void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, NodeTy* Pred,
                                   NodeSet& Dst);
index b70e21977bec583c69e84c343a40c8a2fd031f3b..bf0d5ea39551c0ae948868abd16ddba100e58ba1 100644 (file)
@@ -1190,6 +1190,50 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
   MakeNode(Dst, ME, Pred, St);
 }
 
+void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) {
+
+  Expr* R = S->getRetValue();
+  
+  if (!R) {
+    Dst.Add(Pred);
+    return;
+  }
+  
+  QualType T = R->getType();
+  
+  if (T->isPointerType() || T->isReferenceType()) {
+    
+    // Check if any of the return values return the address of a stack variable.
+    
+    NodeSet Tmp;
+    Visit(R, Pred, Tmp);
+    
+    for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+      RVal X = GetRVal((*I)->getState(), R);
+
+      if (isa<lval::DeclVal>(X)) {
+        
+        if (cast<lval::DeclVal>(X).getDecl()->hasLocalStorage()) {
+        
+          // Create a special node representing the v
+          
+          NodeTy* RetStackNode = Builder->generateNode(S, GetState(*I), *I);
+          
+          if (RetStackNode) {
+            RetStackNode->markAsSink();
+            RetsStackAddr.insert(RetStackNode);
+          }
+          
+          continue;
+        }
+      }
+      
+      Dst.Add(*I);
+    }
+  }
+  else
+    Visit(R, Pred, Dst);
+}
 
 void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
                                        GRExprEngine::NodeTy* Pred,
@@ -1625,14 +1669,8 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
       //  that users can quickly query what was the state at the
       //  exit points of a function.
       
-    case Stmt::ReturnStmtClass: {
-      if (Expr* R = cast<ReturnStmt>(S)->getRetValue())
-        Visit(R, Pred, Dst);
-      else
-        Dst.Add(Pred);
-      
-      break;
-    }
+    case Stmt::ReturnStmtClass:
+      VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst); break;
       
     case Stmt::UnaryOperatorClass: {
       UnaryOperator* U = cast<UnaryOperator>(S);
index 94cedc03529ffa264bf9d075ee584194fa24c165..697d256119d164a48485cd8fe3a8ae524ffe5dda 100644 (file)
@@ -166,6 +166,11 @@ unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx,
               CheckerState->undef_receivers_begin(),
               CheckerState->undef_receivers_end(),
               "Receiver in message expression is an uninitialized value.");
+  
+  EmitWarning(Diag, SrcMgr,
+              CheckerState->ret_stackaddr_begin(),
+              CheckerState->ret_stackaddr_end(),
+              "Address of stack-allocated variable returned.");
 
   FoundationCheck.get()->ReportResults(Diag);
 #ifndef NDEBUG
diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c
new file mode 100644 (file)
index 0000000..55c542c
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: clang -grsimple -verify %s
+
+int* f1() {
+  int x = 0;
+  return &x; // expected-warning{{Address of stack-allocated variable returned.}} expected-warning{{address of stack memory associated with local variable 'x' returned}}
+}
+
+int* f2(int y) {
+  return &y;  // expected-warning{{Address of stack-allocated variable returned.}} expected-warning{{address of stack memory associated with local variable 'y' returned}}
+}
+
+int* f3(int x, int *y) {
+  int w = 0;
+  
+  if (x)
+    y = &w;
+    
+  return y; // expected-warning{{Address of stack-allocated variable returned.}}
+}
+
+