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 | 4af23c81592ce67b1aecde8e58ab1c49a04b3307 (patch) | |
| tree | 567e846bedc8f766a2f78f9d6595d07e461fce5f | |
| parent | 349c3298da272a1b9d3054a239a220a9da949e90 (diff) | |
| download | bcm5719-llvm-4af23c81592ce67b1aecde8e58ab1c49a04b3307.tar.gz bcm5719-llvm-4af23c81592ce67b1aecde8e58ab1c49a04b3307.zip | |
Implements strcasecmp() checker in Static Analyzer.
llvm-svn: 130398
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 33 | ||||
| -rw-r--r-- | clang/test/Analysis/string.c | 84 |
2 files changed, 111 insertions, 6 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 1d25680f072..8e9c7899b0d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/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/clang/test/Analysis/string.c b/clang/test/Analysis/string.c index 9d5c52f57b7..19c838c2556 100644 --- a/clang/test/Analysis/string.c +++ b/clang/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 +} |

