[cfe-commits] r128677 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/CStringChecker.cpp test/Analysis/bstring.c

Lenny Maiorani lenny at colorado.edu
Thu Mar 31 14:36:53 PDT 2011


Author: lenny
Date: Thu Mar 31 16:36:53 2011
New Revision: 128677

URL: http://llvm.org/viewvc/llvm-project?rev=128677&view=rev
Log:
Adding Static Analyzer checker for mempcpy().

Models mempcpy() so that if length is NULL the destination pointer is returned. Otherwise, the source and destination are confirmed not to be NULL and not overlapping. Finally the copy is validated to not cause a buffer overrun and the return value is bound to the address of the byte after the last byte copied.


Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
    cfe/trunk/test/Analysis/bstring.c

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=128677&r1=128676&r2=128677&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Thu Mar 31 16:36:53 2011
@@ -49,11 +49,14 @@
                                           const CallExpr *) const;
 
   void evalMemcpy(CheckerContext &C, const CallExpr *CE) const;
+  void evalMempcpy(CheckerContext &C, const CallExpr *CE) const;
   void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
   void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
-  void evalCopyCommon(CheckerContext &C, const GRState *state,
+  void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
+                      const GRState *state,
                       const Expr *Size, const Expr *Source, const Expr *Dest,
-                      bool Restricted = false) const;
+                      bool Restricted = false,
+                      bool IsMempcpy = false) const;
 
   void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
 
@@ -655,9 +658,12 @@
 // evaluation of individual function calls.
 //===----------------------------------------------------------------------===//
 
-void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
+void CStringChecker::evalCopyCommon(CheckerContext &C, 
+                                    const CallExpr *CE,
+                                    const GRState *state,
                                     const Expr *Size, const Expr *Dest,
-                                    const Expr *Source, bool Restricted) const {
+                                    const Expr *Source, bool Restricted,
+                                    bool IsMempcpy) const {
   // See if the size argument is zero.
   SVal sizeVal = state->getSVal(Size);
   QualType sizeTy = Size->getType();
@@ -665,12 +671,39 @@
   const GRState *stateZeroSize, *stateNonZeroSize;
   llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy);
 
-  // If the size is zero, there won't be any actual memory access.
-  if (stateZeroSize)
+  // Get the value of the Dest.
+  SVal destVal = state->getSVal(Dest);
+
+  // If the size is zero, there won't be any actual memory access, so
+  // just bind the return value to the destination buffer and return.
+  if (stateZeroSize) {
     C.addTransition(stateZeroSize);
+    if (IsMempcpy)
+      state->BindExpr(CE, destVal);
+    else
+      state->BindExpr(CE, sizeVal);
+    return;
+  }
 
   // If the size can be nonzero, we have to check the other arguments.
   if (stateNonZeroSize) {
+
+    // Ensure the destination is not null. If it is NULL there will be a
+    // NULL pointer dereference.
+    state = checkNonNull(C, state, Dest, destVal);
+    if (!state)
+      return;
+
+    // Get the value of the Src.
+    SVal srcVal = state->getSVal(Source);
+    
+    // Ensure the source is not null. If it is NULL there will be a
+    // NULL pointer dereference.
+    state = checkNonNull(C, state, Source, srcVal);
+    if (!state)
+      return;
+
+    // Ensure the buffers do not overlap.
     state = stateNonZeroSize;
     state = CheckBufferAccess(C, state, Size, Dest, Source,
                               /* FirstIsDst = */ true);
@@ -678,6 +711,26 @@
       state = CheckOverlap(C, state, Size, Dest, Source);
 
     if (state) {
+
+      // If this is mempcpy, get the byte after the last byte copied and 
+      // bind the expr.
+      if (IsMempcpy) {
+        loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal);
+        
+        // Get the length to copy.
+        SVal lenVal = state->getSVal(Size);
+        NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&lenVal);
+        
+        // Get the byte after the last byte copied.
+        SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add, 
+                                                          *destRegVal,
+                                                          *lenValNonLoc, 
+                                                          Dest->getType());
+        
+        // The byte after the last byte copied is the return value.
+        state = state->BindExpr(CE, lastElement);
+      }
+
       // Invalidate the destination.
       // FIXME: Even if we can't perfectly model the copy, we should see if we
       // can use LazyCompoundVals to copy the source values into the destination.
@@ -696,7 +749,16 @@
   const Expr *Dest = CE->getArg(0);
   const GRState *state = C.getState();
   state = state->BindExpr(CE, state->getSVal(Dest));
-  evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1), true);
+  evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true);
+}
+
+void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
+  // void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
+  // The return value is a pointer to the byte following the last written byte.
+  const Expr *Dest = CE->getArg(0);
+  const GRState *state = C.getState();
+  
+  evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true);
 }
 
 void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
@@ -705,12 +767,13 @@
   const Expr *Dest = CE->getArg(0);
   const GRState *state = C.getState();
   state = state->BindExpr(CE, state->getSVal(Dest));
-  evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1));
+  evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1));
 }
 
 void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
   // void bcopy(const void *src, void *dst, size_t n);
-  evalCopyCommon(C, C.getState(), CE->getArg(2), CE->getArg(1), CE->getArg(0));
+  evalCopyCommon(C, CE, C.getState(), 
+                 CE->getArg(2), CE->getArg(1), CE->getArg(0));
 }
 
 void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
@@ -982,6 +1045,7 @@
 
   FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
     .Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy)
+    .Case("mempcpy", &CStringChecker::evalMempcpy)
     .Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
     .Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
     .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)

Modified: cfe/trunk/test/Analysis/bstring.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/bstring.c?rev=128677&r1=128676&r2=128677&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/bstring.c (original)
+++ cfe/trunk/test/Analysis/bstring.c Thu Mar 31 16:36:53 2011
@@ -129,10 +129,111 @@
 void memcpy12() {
   char a[4] = {0};
   memcpy(0, a, 0); // no-warning
+}
+
+void memcpy13() {
+  char a[4] = {0};
   memcpy(a, 0, 0); // no-warning
 }
 
 //===----------------------------------------------------------------------===
+// mempcpy()
+//===----------------------------------------------------------------------===
+
+#define mempcpy BUILTIN(mempcpy)
+void *mempcpy(void *restrict s1, const void *restrict s2, size_t n);
+
+void mempcpy0 () {
+  char src[] = {1, 2, 3, 4};
+  char dst[5] = {0};
+
+  mempcpy(dst, src, 4); // no-warning
+
+  if (mempcpy(dst, src, 4) != &dst[4]) {
+    (void)*(char*)0; // no-warning
+  }
+
+  if (dst[0] != 0)
+    (void)*(char*)0; // expected-warning{{null}}
+}
+
+void mempcpy1 () {
+  char src[] = {1, 2, 3, 4};
+  char dst[10];
+
+  mempcpy(dst, src, 5); // expected-warning{{Byte string function accesses out-of-bound array element}}
+}
+
+void mempcpy2 () {
+  char src[] = {1, 2, 3, 4};
+  char dst[1];
+
+  mempcpy(dst, src, 4); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void mempcpy3 () {
+  char src[] = {1, 2, 3, 4};
+  char dst[3];
+
+  mempcpy(dst+1, src+2, 2); // no-warning
+}
+
+void mempcpy4 () {
+  char src[] = {1, 2, 3, 4};
+  char dst[10];
+
+  mempcpy(dst+2, src+2, 3); // expected-warning{{Byte string function accesses out-of-bound array element}}
+}
+
+void mempcpy5() {
+  char src[] = {1, 2, 3, 4};
+  char dst[3];
+
+  mempcpy(dst+2, src+2, 2); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void mempcpy6() {
+  int a[4] = {0};
+  mempcpy(a, a, 8); // expected-warning{{overlapping}}  
+}
+
+void mempcpy7() {
+  int a[4] = {0};
+  mempcpy(a+2, a+1, 8); // expected-warning{{overlapping}}
+}
+
+void mempcpy8() {
+  int a[4] = {0};
+  mempcpy(a+1, a+2, 8); // expected-warning{{overlapping}}
+}
+
+void mempcpy9() {
+  int a[4] = {0};
+  mempcpy(a+2, a+1, 4); // no-warning
+  mempcpy(a+1, a+2, 4); // no-warning
+}
+
+void mempcpy10() {
+  char a[4] = {0};
+  mempcpy(0, a, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void mempcpy11() {
+  char a[4] = {0};
+  mempcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void mempcpy12() {
+  char a[4] = {0};
+  mempcpy(0, a, 0); // no-warning
+}
+
+void mempcpy13() {
+  char a[4] = {0};
+  mempcpy(a, 0, 0); // no-warning
+}
+
+//===----------------------------------------------------------------------===
 // memmove()
 //===----------------------------------------------------------------------===
 





More information about the cfe-commits mailing list