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

Lenny Maiorani lenny at colorado.edu
Tue Apr 12 10:08:43 PDT 2011


Author: lenny
Date: Tue Apr 12 12:08:43 2011
New Revision: 129364

URL: http://llvm.org/viewvc/llvm-project?rev=129364&view=rev
Log:
This patch adds modeling of strcmp() to the CString checker. Validates inputs are not NULL and are real C strings, then does the comparison and binds the proper return value. Unit tests included. 

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=129364&r1=129363&r2=129364&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Tue Apr 12 12:08:43 2011
@@ -74,6 +74,8 @@
   void evalStrcat(CheckerContext &C, const CallExpr *CE) const;
   void evalStrncat(CheckerContext &C, const CallExpr *CE) const;
 
+  void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
+
   // Utility methods
   std::pair<const GRState*, const GRState*>
   static assumeZero(CheckerContext &C,
@@ -87,6 +89,11 @@
   SVal getCStringLength(CheckerContext &C, const GRState *&state,
                         const Expr *Ex, SVal Buf) const;
 
+  const StringLiteral *getCStringLiteral(CheckerContext &C, 
+                                         const GRState *&state,
+                                         const Expr *expr,  
+                                         SVal val) const;
+
   static const GRState *InvalidateBuffer(CheckerContext &C,
                                          const GRState *state,
                                          const Expr *Ex, SVal V);
@@ -587,6 +594,26 @@
   }
 }
 
+const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
+  const GRState *&state, const Expr *expr, SVal val) const {
+
+  // Get the memory region pointed to by the val.
+  const MemRegion *bufRegion = val.getAsRegion();
+  if (!bufRegion)
+    return NULL; 
+
+  // Strip casts off the memory region.
+  bufRegion = bufRegion->StripCasts();
+
+  // Cast the memory region to a string region.
+  const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
+  if (!strRegion)
+    return NULL; 
+
+  // Return the actual string in the string region.
+  return strRegion->getStringLiteral();
+}
+
 const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C,
                                                 const GRState *state,
                                                 const Expr *E, SVal V) {
@@ -1074,6 +1101,61 @@
   C.addTransition(state);
 }
 
+void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
+  //int strcmp(const char *restrict s1, const char *restrict s2);
+
+  const GRState *state = C.getState();
+
+  // Check that the first string is non-null
+  const Expr *s1 = CE->getArg(0);
+  SVal s1Val = state->getSVal(s1);
+  state = checkNonNull(C, state, s1, s1Val);
+  if (!state)
+    return;
+
+  // Check that the second string is non-null.
+  const Expr *s2 = CE->getArg(1);
+  SVal s2Val = state->getSVal(s2);
+  state = checkNonNull(C, state, s2, s2Val);
+  if (!state)
+    return;
+
+  // Get the string length of the first string or give up.
+  SVal s1Length = getCStringLength(C, state, s1, s1Val);
+  if (s1Length.isUndef())
+    return;
+
+  // Get the string length of the second string or give up.
+  SVal s2Length = getCStringLength(C, state, s2, s2Val);
+  if (s2Length.isUndef())
+    return;
+
+  // Get the string literal of the first string.
+  const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val);
+  if (!s1StrLiteral)
+    return;
+  llvm::StringRef s1StrRef = s1StrLiteral->getString();
+
+  // Get the string literal of the second string.
+  const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val);
+  if (!s2StrLiteral)
+    return;
+  llvm::StringRef s2StrRef = s2StrLiteral->getString();
+
+  // Compare string 1 to string 2 the same way strcmp() does.
+  int result = s1StrRef.compare(s2StrRef);
+  
+  // Build the SVal of the comparison to bind the return value.
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  QualType intTy = svalBuilder.getContext().IntTy;
+  SVal resultVal = svalBuilder.makeIntVal(result, intTy);
+
+  // Bind the return value of the expression.
+  // Set the return value.
+  state = state->BindExpr(CE, resultVal);
+  C.addTransition(state);
+}
+
 //===----------------------------------------------------------------------===//
 // The driver method, and other Checker callbacks.
 //===----------------------------------------------------------------------===//
@@ -1108,6 +1190,7 @@
     .Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat)
     .Case("strlen", &CStringChecker::evalstrLength)
     .Case("strnlen", &CStringChecker::evalstrnLength)
+    .Case("strcmp", &CStringChecker::evalStrcmp)
     .Case("bcopy", &CStringChecker::evalBcopy)
     .Default(NULL);
 

Modified: cfe/trunk/test/Analysis/string.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/string.c?rev=129364&r1=129363&r2=129364&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/string.c (original)
+++ cfe/trunk/test/Analysis/string.c Tue Apr 12 12:08:43 2011
@@ -596,3 +596,89 @@
   if (strlen(y) == 4)
     strncat(x, y, 1); // no-warning
 }
+
+//===----------------------------------------------------------------------===
+// strcmp()
+//===----------------------------------------------------------------------===
+
+#define strcmp BUILTIN(strcmp)
+int strcmp(const char *restrict s1, const char *restrict s2);
+
+void strcmp_constant0() {
+  if (strcmp("123", "123") != 0)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_constant_and_var_0() {
+  char *x = "123";
+  if (strcmp(x, "123") != 0)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_constant_and_var_1() {
+  char *x = "123";
+    if (strcmp("123", x) != 0)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_0() {
+  char *x = "123";
+  char *y = "123";
+  if (strcmp(x, y) != 0)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_1() {
+  char *x = "234";
+  char *y = "123";
+  if (strcmp(x, y) != 1)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_2() {
+  char *x = "123";
+  char *y = "234";
+  if (strcmp(x, y) != -1)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_null_0() {
+  char *x = NULL;
+  char *y = "123";
+  strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcmp_null_1() {
+  char *x = "123";
+  char *y = NULL;
+  strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcmp_diff_length_0() {
+  char *x = "12345";
+  char *y = "234";
+  if (strcmp(x, y) != -1)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_diff_length_1() {
+  char *x = "123";
+  char *y = "23456";
+  if (strcmp(x, y) != -1)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_diff_length_2() {
+  char *x = "12345";
+  char *y = "123";
+  if (strcmp(x, y) != 1)
+    (void)*(char*)0; // no-warning
+}
+
+void strcmp_diff_length_3() {
+  char *x = "123";
+  char *y = "12345";
+  if (strcmp(x, y) != -1)
+    (void)*(char*)0; // no-warning
+}
+





More information about the cfe-commits mailing list