From: Lenny Maiorani Date: Mon, 2 May 2011 19:05:49 +0000 (+0000) Subject: Implements strncasecmp() checker and simplifies some of the logic around creating... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=454fd2d3a1b6d0ef225c5d3927c1ad3b97510d1a;p=clang Implements strncasecmp() checker and simplifies some of the logic around creating substrings if necessary and calling the appropriate StringRef::compare/compare_lower(). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130708 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index a6a256a87b..4f9c641edf 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -77,6 +77,7 @@ 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 evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, bool isBounded = false, bool ignoreCase = false) const; @@ -1128,6 +1129,12 @@ void CStringChecker::evalStrcasecmp(CheckerContext &C, evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true); } +void CStringChecker::evalStrncasecmp(CheckerContext &C, + const CallExpr *CE) const { + //int strncasecmp(const char *restrict s1, const char *restrict s2, size_t n); + evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true); +} + void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, bool isBounded, bool ignoreCase) const { const GRState *state = C.getState(); @@ -1181,31 +1188,17 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, return; llvm::APSInt lenInt(CI->getValue()); - // Compare using the bounds provided like strncmp() does. - if (ignoreCase) { - // TODO Implement compare_lower(RHS, n) in LLVM StringRef. - // result = s1StrRef.compare_lower(s2StrRef, - // (size_t)lenInt.getLimitedValue()); + // Create substrings of each to compare the prefix. + s1StrRef = s1StrRef.substr(0, (size_t)lenInt.getLimitedValue()); + s2StrRef = s2StrRef.substr(0, (size_t)lenInt.getLimitedValue()); + } - // For now, give up. - return; - } else { - // Create substrings of each to compare the prefix. - llvm::StringRef s1SubStr = - s1StrRef.substr(0, (size_t)lenInt.getLimitedValue()); - llvm::StringRef s2SubStr = - s2StrRef.substr(0, (size_t)lenInt.getLimitedValue()); - - // Compare the substrings. - result = s1SubStr.compare(s2SubStr); - } + if (ignoreCase) { + // Compare string 1 to string 2 the same way strcasecmp() does. + result = s1StrRef.compare_lower(s2StrRef); } else { // Compare string 1 to string 2 the same way strcmp() does. - if (ignoreCase) { - result = s1StrRef.compare_lower(s2StrRef); - } else { - result = s1StrRef.compare(s2StrRef); - } + result = s1StrRef.compare(s2StrRef); } // Build the SVal of the comparison to bind the return value. @@ -1256,6 +1249,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { .Case("strcmp", &CStringChecker::evalStrcmp) .Case("strncmp", &CStringChecker::evalStrncmp) .Case("strcasecmp", &CStringChecker::evalStrcasecmp) + .Case("strncasecmp", &CStringChecker::evalStrncasecmp) .Case("bcopy", &CStringChecker::evalBcopy) .Default(NULL); diff --git a/test/Analysis/string.c b/test/Analysis/string.c index 19c838c255..40afacc438 100644 --- a/test/Analysis/string.c +++ b/test/Analysis/string.c @@ -872,3 +872,109 @@ void strcasecmp_diff_length_3() { if (strcasecmp(x, y) != -1) (void)*(char*)0; // no-warning } + +//===----------------------------------------------------------------------=== +// strncasecmp() +//===----------------------------------------------------------------------=== + +#define strncasecmp BUILTIN(strncasecmp) +int strncasecmp(const char *restrict s1, const char *restrict s2, size_t n); + +void strncasecmp_constant0() { + if (strncasecmp("abc", "Abc", 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_constant_and_var_0() { + char *x = "abc"; + if (strncasecmp(x, "Abc", 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_constant_and_var_1() { + char *x = "abc"; + if (strncasecmp("Abc", x, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_0() { + char *x = "abc"; + char *y = "Abc"; + if (strncasecmp(x, y, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_1() { + char *x = "Bcd"; + char *y = "abc"; + if (strncasecmp(x, y, 3) != 1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_2() { + char *x = "abc"; + char *y = "Bcd"; + if (strncasecmp(x, y, 3) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_null_0() { + char *x = NULL; + char *y = "123"; + strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}} +} + +void strncasecmp_null_1() { + char *x = "123"; + char *y = NULL; + strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}} +} + +void strncasecmp_diff_length_0() { + char *x = "abcde"; + char *y = "aBd"; + if (strncasecmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_1() { + char *x = "abc"; + char *y = "aBdef"; + if (strncasecmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_2() { + char *x = "aBcDe"; + char *y = "abc"; + if (strncasecmp(x, y, 5) != 1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_3() { + char *x = "aBc"; + char *y = "abcde"; + if (strncasecmp(x, y, 5) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_4() { + char *x = "abcde"; + char *y = "aBc"; + if (strncasecmp(x, y, 3) != 0) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_5() { + char *x = "abcde"; + char *y = "aBd"; + if (strncasecmp(x, y, 3) != -1) + (void)*(char*)0; // no-warning +} + +void strncasecmp_diff_length_6() { + char *x = "aBDe"; + char *y = "abc"; + if (strncasecmp(x, y, 3) != 1) + (void)*(char*)0; // no-warning +}