[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