]> granicus.if.org Git - clang/commitdiff
[static analyzer] Extend VLA size checking to look for undefined sizes.
authorTed Kremenek <kremenek@apple.com>
Tue, 9 Dec 2008 00:44:16 +0000 (00:44 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 9 Dec 2008 00:44:16 +0000 (00:44 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60734 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/PathSensitive/GRExprEngine.h
lib/Analysis/GRExprEngine.cpp
lib/Analysis/GRExprEngineInternalChecks.cpp
test/Analysis/misc-ps.m

index 80165c5686a5647ae2d23e84a6174460d2385823..6f86102ae1552ccf593b195976e60c0f052eb014 100644 (file)
@@ -139,13 +139,13 @@ public:
   ///  MUST be zero or undefined.
   ErrorNodes ExplicitBadDivides;
   
-  /// ImplicitZeroSizedVLA - Nodes in the ExplodedGraph that result from 
+  /// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from 
   ///  constructing a zero-sized VLA where the size may be zero.
-  ErrorNodes ImplicitZeroSizedVLA;
+  ErrorNodes ImplicitBadSizedVLA;
   
-  /// ExplicitZeroSizedVLA - Nodes in the ExplodedGraph that result from 
+  /// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from 
   ///  constructing a zero-sized VLA where the size must be zero.
-  ErrorNodes ExplicitZeroSizedVLA;
+  ErrorNodes ExplicitBadSizedVLA;
   
   /// UndefResults - Nodes in the ExplodedGraph where the operands are defined
   ///  by the result is not.  Excludes divide-by-zero errors.
@@ -453,7 +453,7 @@ protected:
   const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
     return StateMgr.BindLoc(St, LV, V);
   }
-  
+
   SVal GetSVal(const GRState* St, Stmt* Ex) {
     return StateMgr.GetSVal(St, Ex);
   }
index fb520675734d5d2495905e64658d79be40f3a658..343ac697a30278fcb3359eae54c2b0ff14ff787b 100644 (file)
@@ -1820,6 +1820,14 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
       
       Expr* SE = VLA->getSizeExpr();
       SVal Size = GetSVal(St, SE);
+      
+      if (Size.isUndef()) {
+        if (NodeTy* N = Builder->generateNode(DS, St, Pred)) {
+          N->markAsSink();          
+          ExplicitBadSizedVLA.insert(N);
+        }
+        continue;
+      }
 
       bool isFeasibleZero = false;
       const GRState* ZeroSt =  Assume(St, Size, false, isFeasibleZero);
@@ -1830,8 +1838,8 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
       if (isFeasibleZero) {
         if (NodeTy* N = Builder->generateNode(DS, ZeroSt, Pred)) {
           N->markAsSink();          
-          if (isFeasibleNotZero) ImplicitZeroSizedVLA.insert(N);
-          else ExplicitZeroSizedVLA.insert(N);
+          if (isFeasibleNotZero) ImplicitBadSizedVLA.insert(N);
+          else ExplicitBadSizedVLA.insert(N);
         }
       }
       
index 8b484ab10c0d29482fc1d744f10b975c57bf028a..d32318ca7d91d4605ec93f2f4bed9b77e5cd62f3 100644 (file)
@@ -40,6 +40,7 @@ ExplodedNode<GRState>* GetNode(GRExprEngine::undef_arg_iterator I) {
 
 namespace {
 class VISIBILITY_HIDDEN BuiltinBug : public BugTypeCacheLocation {
+protected:
   const char* name;
   const char* desc;
 public:
@@ -332,26 +333,45 @@ public:
   }
 };
   
-class VISIBILITY_HIDDEN ZeroSizeVLA : public BuiltinBug {
+class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug {
 
 public:
-  ZeroSizeVLA() : BuiltinBug("Zero-sized VLA",  
+  BadSizeVLA() : BuiltinBug("Zero-sized VLA",  
                              "VLAs with zero-size are undefined.") {}
   
   virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
     for (GRExprEngine::ErrorNodes::iterator
-          I = Eng.ExplicitZeroSizedVLA.begin(),
-          E = Eng.ExplicitZeroSizedVLA.end(); I!=E; ++I) {
-      
-      // Generate a report for this bug.
-      PostStmt PS = cast<PostStmt>((*I)->getLocation());      
+          I = Eng.ExplicitBadSizedVLA.begin(),
+          E = Eng.ExplicitBadSizedVLA.end(); I!=E; ++I) {
+
+      // Determine whether this was a 'zero-sized' VLA or a VLA with an
+      // undefined size.
+      GRExprEngine::NodeTy* N = *I;
+      PostStmt PS = cast<PostStmt>(N->getLocation());      
       DeclStmt *DS = cast<DeclStmt>(PS.getStmt());
       VarDecl* VD = cast<VarDecl>(*DS->decl_begin());
       QualType T = Eng.getContext().getCanonicalType(VD->getType());
       VariableArrayType* VT = cast<VariableArrayType>(T);
+      Expr* SizeExpr = VT->getSizeExpr();
       
-      RangedBugReport report(*this, *I);
-      report.addRange(VT->getSizeExpr()->getSourceRange());
+      std::string buf;
+      llvm::raw_string_ostream os(buf);
+      os << "The expression used to specify the number of elements in the VLA '"
+          << VD->getNameAsString() << "' evaluates to ";
+      
+      SVal X = Eng.getStateManager().GetSVal(N->getState(), SizeExpr);
+      if (X.isUndef()) {
+        name = "Undefined size for VLA";
+        os << "an undefined or garbage value.";
+      }
+      else {
+        name = "Zero-sized VLA";
+        os << " to 0.  VLAs with no elements have undefined behavior.";
+      }
+
+      desc = os.str().c_str();
+      RangedBugReport report(*this, N);
+      report.addRange(SizeExpr->getSourceRange());
       
       // Emit the warning.
       BR.EmitWarning(report);
@@ -430,6 +450,6 @@ void GRExprEngine::RegisterInternalChecks() {
   Register(new BadMsgExprArg());
   Register(new BadReceiver());
   Register(new OutOfBoundMemoryAccess());
-  Register(new ZeroSizeVLA());
+  Register(new BadSizeVLA());
   AddCheck(new CheckAttrNonNull(), Stmt::CallExprClass); 
 }
index 40322f1f0c55a55d65a432f68046edaf9f312148..be697f8f3a5ebf3c78620cfa537352b800cc2c23 100644 (file)
@@ -79,6 +79,11 @@ void check_zero_sized_VLA(int x) {
   if (x)
     return;
 
-  int vla[x]; // expected-warning{{VLAs with zero-size are undefined}}
+  int vla[x]; // expected-warning{{VLAs with no elements have undefined behavior}}
+}
+
+void check_uninit_sized_VLA() {
+  int x;
+  int vla[x]; // expected-warning{{The expression used to specify the number of elements in the VLA 'vla' evaluates to an undefined or garbage value.}}
 }