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

Ted Kremenek kremenek at apple.com
Mon Feb 21 20:58:34 PST 2011


Author: kremenek
Date: Mon Feb 21 22:58:34 2011
New Revision: 126188

URL: http://llvm.org/viewvc/llvm-project?rev=126188&view=rev
Log:
Add CStringChecker support for strncpy.  Patch by Lenny Maiorani!

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

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=126188&r1=126187&r2=126188&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Mon Feb 21 22:58:34 2011
@@ -59,8 +59,10 @@
                            bool IsStrnlen = false);
 
   void evalStrcpy(CheckerContext &C, const CallExpr *CE);
+  void evalStrncpy(CheckerContext &C, const CallExpr *CE);
   void evalStpcpy(CheckerContext &C, const CallExpr *CE);
-  void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd);
+  void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd,
+                        bool isStrncpy);
 
   // Utility methods
   std::pair<const GRState*, const GRState*>
@@ -845,16 +847,21 @@
 
 void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) {
   // char *strcpy(char *restrict dst, const char *restrict src);
-  evalStrcpyCommon(C, CE, /* returnEnd = */ false);
+  evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ false);
+}
+
+void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) {
+  // char *strcpy(char *restrict dst, const char *restrict src);
+  evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ true);
 }
 
 void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) {
   // char *stpcpy(char *restrict dst, const char *restrict src);
-  evalStrcpyCommon(C, CE, /* returnEnd = */ true);
+  evalStrcpyCommon(C, CE, /* returnEnd = */ true, /* isStrncpy = */ false);
 }
 
 void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
-                                      bool returnEnd) {
+                                      bool returnEnd, bool isStrncpy) {
   const GRState *state = C.getState();
 
   // Check that the destination is non-null
@@ -879,6 +886,31 @@
   if (strLength.isUndef())
     return;
 
+  if (isStrncpy) {
+    // Get the max number of characters to copy
+    const Expr *lenExpr = CE->getArg(2);
+    SVal lenVal = state->getSVal(lenExpr);
+
+    NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
+    NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal);
+
+    QualType cmpTy = C.getSValBuilder().getContext().IntTy;
+    const GRState *stateTrue, *stateFalse;
+    
+    // Check if the max number to copy is less than the length of the src
+    llvm::tie(stateTrue, stateFalse) =
+      state->assume(cast<DefinedOrUnknownSVal>
+                    (C.getSValBuilder().evalBinOpNN(state, BO_GT, 
+                                                    *strLengthNL, *lenValNL,
+                                                    cmpTy)));
+
+    if (stateTrue) {
+      // Max number to copy is less than the length of the src, so the actual
+      // strLength copied is the max number arg.
+      strLength = lenVal;
+    }    
+  }
+
   SVal Result = (returnEnd ? UnknownVal() : DstVal);
 
   // If the destination is a MemRegion, try to check for a buffer overflow and
@@ -951,6 +983,7 @@
     .Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
     .Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
     .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
+    .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
     .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
     .Case("strlen", &CStringChecker::evalstrLength)
     .Case("strnlen", &CStringChecker::evalstrnLength)

Modified: cfe/trunk/test/Analysis/string.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/string.c?rev=126188&r1=126187&r2=126188&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/string.c (original)
+++ cfe/trunk/test/Analysis/string.c Mon Feb 21 22:58:34 2011
@@ -328,6 +328,74 @@
 }
 
 //===----------------------------------------------------------------------===
+// strncpy()
+//===----------------------------------------------------------------------===
+
+#ifdef VARIANT
+
+#define __strncpy_chk BUILTIN(__strncpy_chk)
+char *__strncpy_chk(char *restrict s1, const char *restrict s2, size_t n, size_t destlen);
+
+#define strncpy(a,b,c) __strncpy_chk(a,b,c, (size_t)-1)
+
+#else /* VARIANT */
+
+#define strncpy BUILTIN(strncpy)
+char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
+
+#endif /* VARIANT */
+
+
+void strncpy_null_dst(char *x) {
+  strncpy(NULL, x, 1); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strncpy_null_src(char *x) {
+  strncpy(x, NULL, 1); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strncpy_fn(char *x) {
+  strncpy(x, (char*)&strncpy_fn, 1); // expected-warning{{Argument to byte string function is the address of the function 'strncpy_fn', which is not a null-terminated string}}
+}
+
+void strncpy_effects(char *x, char *y) {
+  char a = x[0];
+
+  if (strncpy(x, y, strlen(y)) != x)
+    (void)*(char*)0; // no-warning
+
+  if (strlen(x) != strlen(y))
+    (void)*(char*)0; // no-warning
+
+  if (a != x[0])
+    (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strncpy_overflow(char *y) {
+  char x[4];
+  if (strlen(y) == 4)
+    strncpy(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void strncpy_len_overflow(char *y) {
+  char x[4];
+  if (strlen(y) == 3)
+    strncpy(x, y, sizeof(x)); // no-warning
+}
+
+void strncpy_no_overflow(char *y) {
+  char x[4];
+  if (strlen(y) == 3)
+    strncpy(x, y, strlen(y)); // no-warning
+}
+
+void strncpy_no_len_overflow(char *y) {
+  char x[4];
+  if (strlen(y) == 4)
+    strncpy(x, y, sizeof(x)-1); // no-warning
+}
+
+//===----------------------------------------------------------------------===
 // stpcpy()
 //===----------------------------------------------------------------------===
 





More information about the cfe-commits mailing list