]> granicus.if.org Git - clang/commitdiff
Track extents for VLAs.
authorJordy Rose <jediknil@belkadan.com>
Mon, 5 Jul 2010 00:50:15 +0000 (00:50 +0000)
committerJordy Rose <jediknil@belkadan.com>
Mon, 5 Jul 2010 00:50:15 +0000 (00:50 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107603 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Checker/MemRegion.cpp
lib/Checker/VLASizeChecker.cpp
test/Analysis/outofbound.c

index 6a60a61bfabe6e522cb73c8ad0aba94fb077e8e6..b0e57fd251eccd323e14e0e3c28b8d332f24a131 100644 (file)
@@ -179,8 +179,9 @@ DefinedOrUnknownSVal DeclRegion::getExtent(ValueManager& ValMgr) const {
   ASTContext& Ctx = ValMgr.getContext();
   QualType T = getDesugaredValueType(Ctx);
 
-  // FIXME: Handle variable-length arrays.
-  if (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
+  if (isa<VariableArrayType>(T))
+    return nonloc::SymbolVal(ValMgr.getSymbolManager().getExtentSymbol(this));
+  if (isa<IncompleteArrayType>(T))
     return UnknownVal();
 
   CharUnits Size = Ctx.getTypeSizeInChars(T);
index cea9d191aa77c41465414d0769b3adad225a6aa0..dfb606b8b88d88e29f54f3a065e1a1d591c9086e 100644 (file)
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "GRExprEngineInternalChecks.h"
+#include "clang/AST/CharUnits.h"
 #include "clang/Checker/BugReporter/BugType.h"
 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
 #include "clang/Checker/PathSensitive/GRExprEngine.h"
@@ -42,9 +43,9 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
   const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
   if (!VD)
     return;
-  
-  const VariableArrayType *VLA
-    = C.getASTContext().getAsVariableArrayType(VD->getType());
+
+  ASTContext &Ctx = C.getASTContext();
+  const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType());
   if (!VLA)
     return;
 
@@ -70,9 +71,14 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
     C.EmitReport(report);
     return;
   }
+
+  // See if the size value is known. It can't be undefined because we would have
+  // warned about that already.
+  if (sizeV.isUnknown())
+    return;
   
   // Check if the size is zero.
-  DefinedOrUnknownSVal sizeD = cast<DefinedOrUnknownSVal>(sizeV);
+  DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
 
   const GRState *stateNotZero, *stateZero;
   llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD);
@@ -92,5 +98,29 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
   }
  
   // From this point on, assume that the size is not zero.
-  C.addTransition(stateNotZero);
+  state = stateNotZero;
+
+  // Convert the array length to size_t.
+  ValueManager &ValMgr = C.getValueManager();
+  SValuator &SV = ValMgr.getSValuator();
+  QualType SizeTy = Ctx.getSizeType();
+  NonLoc ArrayLength = cast<NonLoc>(SV.EvalCast(sizeD, SizeTy, SE->getType()));
+
+  // Get the element size.
+  CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
+  SVal EleSizeVal = ValMgr.makeIntVal(EleSize.getQuantity(), SizeTy);
+
+  // Multiply the array length by the element size.
+  SVal ArraySizeVal = SV.EvalBinOpNN(state, BinaryOperator::Mul, ArrayLength,
+                                     cast<NonLoc>(EleSizeVal), SizeTy);
+
+  // Finally, Assume that the array's extent matches the given size.
+  const LocationContext *LC = C.getPredecessor()->getLocationContext();
+  DefinedOrUnknownSVal Extent = state->getRegion(VD, LC)->getExtent(ValMgr);
+  DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal);
+  DefinedOrUnknownSVal SizeIsKnown = SV.EvalEQ(state, Extent, ArraySize);
+  state = state->Assume(SizeIsKnown, true);
+
+  // Remember our assumptions!
+  C.addTransition(state);
 }
index 305d5e56cbb1cf29327171efb7615e3f80eaac98..8ffb3e1efbf2a6c78516ae8e21ea91587622a935 100644 (file)
@@ -54,3 +54,11 @@ void f7() {
   struct three_words a;
   a.c[3] = 1; // expected-warning{{out-of-bound}}
 }
+
+void vla(int a) {
+  if (a == 5) {
+    int x[a];
+    x[4] = 4; // no-warning
+    x[5] = 5; // expected-warning{{out-of-bound}}
+  }
+}