diff options
author | Lenny Maiorani <lenny@colorado.edu> | 2011-04-28 15:09:11 +0000 |
---|---|---|
committer | Lenny Maiorani <lenny@colorado.edu> | 2011-04-28 15:09:11 +0000 |
commit | bd1d16a1792cd6ea5ede9869e18d781e3fc1a8c3 (patch) | |
tree | 92d56683b5512d9e14c3566d0d929e5211102f4b | |
parent | 75c4064932d481ac710a80aa88b3370ad8a6af1d (diff) |
Implements strcasecmp() checker in Static Analyzer.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130398 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 33 | ||||
-rw-r--r-- | test/Analysis/string.c | 84 |
2 files changed, 111 insertions, 6 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 1d25680f07..8e9c7899b0 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -76,8 +76,9 @@ public: void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; + void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, - bool isBounded = false) const; + bool isBounded = false, bool ignoreCase = false) const; // Utility methods std::pair<const GRState*, const GRState*> @@ -1106,16 +1107,22 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { //int strcmp(const char *restrict s1, const char *restrict s2); - evalStrcmpCommon(C, CE, /* isBounded = */ false); + evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ false); } void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { //int strncmp(const char *restrict s1, const char *restrict s2, size_t n); - evalStrcmpCommon(C, CE, /* isBounded = */ true); + evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false); +} + +void CStringChecker::evalStrcasecmp(CheckerContext &C, + const CallExpr *CE) const { + //int strcasecmp(const char *restrict s1, const char *restrict s2); + evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true); } void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, - bool isBounded) const { + bool isBounded, bool ignoreCase) const { const GRState *state = C.getState(); // Check that the first string is non-null @@ -1168,10 +1175,23 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, llvm::APSInt lenInt(CI->getValue()); // Compare using the bounds provided like strncmp() does. - result = s1StrRef.compare(s2StrRef, (size_t)lenInt.getLimitedValue()); + if (ignoreCase) { + // TODO Implement compare_lower(RHS, n) in LLVM StringRef. + // result = s1StrRef.compare_lower(s2StrRef, + // (size_t)lenInt.getLimitedValue()); + + // For now, give up. + return; + } else { + result = s1StrRef.compare(s2StrRef, (size_t)lenInt.getLimitedValue()); + } } else { // Compare string 1 to string 2 the same way strcmp() does. - result = s1StrRef.compare(s2StrRef); + if (ignoreCase) { + result = s1StrRef.compare_lower(s2StrRef); + } else { + result = s1StrRef.compare(s2StrRef); + } } // Build the SVal of the comparison to bind the return value. @@ -1221,6 +1241,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { .Case("strnlen", &CStringChecker::evalstrnLength) .Case("strcmp", &CStringChecker::evalStrcmp) .Case("strncmp", &CStringChecker::evalStrncmp) + .Case("strcasecmp", &CStringChecker::evalStrcasecmp) .Case("bcopy", &CStringChecker::evalBcopy) .Default(NULL); diff --git a/test/Analysis/string.c b/test/Analysis/string.c index 9d5c52f57b..19c838c255 100644 --- a/test/Analysis/string.c +++ b/test/Analysis/string.c @@ -788,3 +788,87 @@ void strncmp_diff_length_6() { (void)*(char*)0; // no-warning } +//===----------------------------------------------------------------------=== +// strcasecmp() +//===----------------------------------------------------------------------=== + +#define strcasecmp BUILTIN(strcasecmp) +int strcasecmp(const char *restrict s1, const char *restrict s2); + +void strcasecmp_constant0() { + if (strcasecmp("abc", "Abc") != 0) + (void)*(char*)0; // no-warning +} + +void strcasecmp_constant_and_var_0() { + char *x = "abc"; + if (strcasecmp(x, "Abc") != 0) + (void)*(char*)0; // no-warning +} + +void strcasecmp_constant_and_var_1() { + char *x = "abc"; + if (strcasecmp("Abc", x) != 0) + (void)*(char*)0; // no-warning +} + +void strcasecmp_0() { + char *x = "abc"; + char *y = "Abc"; + if (strcasecmp(x, y) != 0) + (void)*(char*)0; // no-warning +} + +void strcasecmp_1() { + char *x = "Bcd"; + char *y = "abc"; + if (strcasecmp(x, y) != 1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_2() { + char *x = "abc"; + char *y = "Bcd"; + if (strcasecmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_null_0() { + char *x = NULL; + char *y = "123"; + strcasecmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}} +} + +void strcasecmp_null_1() { + char *x = "123"; + char *y = NULL; + strcasecmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}} +} + +void strcasecmp_diff_length_0() { + char *x = "abcde"; + char *y = "aBd"; + if (strcasecmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_diff_length_1() { + char *x = "abc"; + char *y = "aBdef"; + if (strcasecmp(x, y) != -1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_diff_length_2() { + char *x = "aBcDe"; + char *y = "abc"; + if (strcasecmp(x, y) != 1) + (void)*(char*)0; // no-warning +} + +void strcasecmp_diff_length_3() { + char *x = "aBc"; + char *y = "abcde"; + if (strcasecmp(x, y) != -1) + (void)*(char*)0; // no-warning +} |