]> granicus.if.org Git - clang/commitdiff
Add trivial buffer overflow checking in Sema.
authorTed Kremenek <kremenek@apple.com>
Wed, 16 Feb 2011 01:57:07 +0000 (01:57 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 16 Feb 2011 01:57:07 +0000 (01:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125640 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
test/Analysis/out-of-bounds.c
test/Sema/array-bounds.c [new file with mode: 0644]

index 84f87f423a7ca84287fc29bcea7386fbb0477823..2c82dcb5fdaa831e02fb832aa366f178004030d2 100644 (file)
@@ -3379,6 +3379,10 @@ def warn_not_compound_assign : Warning<
 def warn_explicit_conversion_functions : Warning<
   "explicit conversion functions are a C++0x extension">, InGroup<CXX0x>;
 
+def warn_array_index_out_of_bounds : Warning<
+  "array index %select{precedes first|excedes last}0 array element">,
+  InGroup<DiagGroup<"array-bounds">>;
+
 def warn_printf_write_back : Warning<
   "use of '%%n' in format string discouraged (potentially insecure)">,
   InGroup<FormatSecurity>;
index e76bd67a3c6dc05f8b96b2899c7fbfd5b6a3af3d..23bcb94976dbb5d489ff14352375f6771cfa3acb 100644 (file)
@@ -5056,7 +5056,8 @@ public:
   SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
                                                 unsigned ByteNo) const;
 
-private:
+private:  
+  void CheckArrayAccess(const ArraySubscriptExpr *ae);
   bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
   bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
 
index 03ce7f3708a7bac7e5ce7871ecab401c319b54ae..ea1f07d783437ab167e00f64c420128486f8799a 100644 (file)
@@ -3080,3 +3080,33 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
     << TRange << Op->getSourceRange();
 }
 
+void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *ae) {
+  const DeclRefExpr *dr =
+    dyn_cast<DeclRefExpr>(ae->getBase()->IgnoreParenImpCasts());
+  if (!dr)
+    return;
+  const VarDecl *vd = cast<VarDecl>(dr->getDecl());
+  const ConstantArrayType *cat = Context.getAsConstantArrayType(vd->getType());
+  if (!cat)
+    return;
+  const Expr *idx = ae->getIdx();
+  if (idx->isValueDependent())
+    return;
+  llvm::APSInt result;
+  if (!idx->isIntegerConstantExpr(result, Context))
+    return;
+  unsigned kind = 2;
+  if (result.slt(0))
+    kind = /* precedes */ 0;
+  else {
+    const llvm::APInt &size = cat->getSize();
+    if (size.getBitWidth() > result.getBitWidth())
+      result = result.sext(size.getBitWidth());
+    if (result.sge(size))
+      kind = /* excedes */ 1;
+  }
+  if (kind < 2)
+    Diag(ae->getBase()->getLocEnd(), diag::warn_array_index_out_of_bounds)
+      << kind << idx->getSourceRange();
+}
+
index b0c337149d9c8a8f3b0e009ce9f1962a242809ce..760d5d58bc4c378a0e166fb105afc6aadfcdccc0 100644 (file)
@@ -294,6 +294,9 @@ void Sema::DefaultLvalueConversion(Expr *&E) {
   if (T.hasQualifiers())
     T = T.getUnqualifiedType();
 
+  if (const ArraySubscriptExpr *ae = dyn_cast<ArraySubscriptExpr>(E))
+    CheckArrayAccess(ae);
+  
   E = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
                                E, 0, VK_RValue);
 }
@@ -7242,6 +7245,11 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
     Diag(UO->getOperatorLoc(), diag::note_indirection_through_null);
   }
   
+  // Check for trivial buffer overflows.
+  if (const ArraySubscriptExpr *ae
+      = dyn_cast<ArraySubscriptExpr>(LHS->IgnoreParenCasts()))
+    CheckArrayAccess(ae);
+  
   // C99 6.5.16p3: The type of an assignment expression is the type of the
   // left operand unless the left operand has qualified type, in which case
   // it is the unqualified version of the type of the left operand.
index d8e4ad915a056e3609ff2ee7590d256284974f0b..b8d6e442ff5714f0a8fd0527a76cc7d3c69bb026 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-check-buffer-overflows -verify %s
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-check-objc-mem -analyzer-check-buffer-overflows -verify %s
 
 // Tests doing an out-of-bounds access after the end of an array using:
 // - constant integer index
diff --git a/test/Sema/array-bounds.c b/test/Sema/array-bounds.c
new file mode 100644 (file)
index 0000000..b540885
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -verify %s
+
+int foo() {
+  int x[2];
+  int y[2];
+  int *p = &y[2]; // no-warning
+  (void) sizeof(x[2]); // no-warning
+  y[2] = 2; // expected-warning{{array index excedes last array element}}
+  return x[2] +  // expected-warning{{array index excedes last array element}}
+         y[-1] + // expected-warning{{array index precedes first array element}}
+         x[sizeof(x)] +  // expected-warning{{array index excedes last array element}}
+         x[sizeof(x) / sizeof(x[0])] +  // expected-warning{{array index excedes last array element}}
+         x[sizeof(x) / sizeof(x[0]) - 1] + // no-warning
+         x[sizeof(x[2])]; // expected-warning{{array index excedes last array element}}
+}
+