summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLenny Maiorani <lenny@colorado.edu>2011-04-28 15:09:11 +0000
committerLenny Maiorani <lenny@colorado.edu>2011-04-28 15:09:11 +0000
commit4af23c81592ce67b1aecde8e58ab1c49a04b3307 (patch)
tree567e846bedc8f766a2f78f9d6595d07e461fce5f
parent349c3298da272a1b9d3054a239a220a9da949e90 (diff)
downloadbcm5719-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.cpp33
-rw-r--r--clang/test/Analysis/string.c84
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
+}
OpenPOWER on IntegriCloud