forked from OSchip/llvm-project
Implements the strncmp() checker just like the strcmp() checker, but with bounds. Requires LLVM svn r129582.
llvm-svn: 130161
This commit is contained in:
parent
f5ba0415df
commit
e553e40467
|
@ -75,6 +75,9 @@ public:
|
||||||
void evalStrncat(CheckerContext &C, const CallExpr *CE) const;
|
void evalStrncat(CheckerContext &C, const CallExpr *CE) const;
|
||||||
|
|
||||||
void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
|
void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
|
||||||
|
void evalStrncmp(CheckerContext &C, const CallExpr *CE) const;
|
||||||
|
void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
|
||||||
|
bool isBounded = false) const;
|
||||||
|
|
||||||
// Utility methods
|
// Utility methods
|
||||||
std::pair<const GRState*, const GRState*>
|
std::pair<const GRState*, const GRState*>
|
||||||
|
@ -1103,7 +1106,16 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
|
||||||
|
|
||||||
void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
|
void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
|
||||||
//int strcmp(const char *restrict s1, const char *restrict s2);
|
//int strcmp(const char *restrict s1, const char *restrict s2);
|
||||||
|
evalStrcmpCommon(C, CE, /* isBounded = */ 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
|
||||||
|
bool isBounded) const {
|
||||||
const GRState *state = C.getState();
|
const GRState *state = C.getState();
|
||||||
|
|
||||||
// Check that the first string is non-null
|
// Check that the first string is non-null
|
||||||
|
@ -1142,8 +1154,25 @@ void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
|
||||||
return;
|
return;
|
||||||
llvm::StringRef s2StrRef = s2StrLiteral->getString();
|
llvm::StringRef s2StrRef = s2StrLiteral->getString();
|
||||||
|
|
||||||
// Compare string 1 to string 2 the same way strcmp() does.
|
int result;
|
||||||
int result = s1StrRef.compare(s2StrRef);
|
if (isBounded) {
|
||||||
|
// Get the max number of characters to compare.
|
||||||
|
const Expr *lenExpr = CE->getArg(2);
|
||||||
|
SVal lenVal = state->getSVal(lenExpr);
|
||||||
|
|
||||||
|
// Dynamically cast the length to a ConcreteInt. If it is not a ConcreteInt
|
||||||
|
// then give up, otherwise get the value and use it as the bounds.
|
||||||
|
nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&lenVal);
|
||||||
|
if (!CI)
|
||||||
|
return;
|
||||||
|
llvm::APSInt lenInt(CI->getValue());
|
||||||
|
|
||||||
|
// Compare using the bounds provided like strncmp() does.
|
||||||
|
result = s1StrRef.compare(s2StrRef, (size_t)lenInt.getLimitedValue());
|
||||||
|
} else {
|
||||||
|
// Compare string 1 to string 2 the same way strcmp() does.
|
||||||
|
result = s1StrRef.compare(s2StrRef);
|
||||||
|
}
|
||||||
|
|
||||||
// Build the SVal of the comparison to bind the return value.
|
// Build the SVal of the comparison to bind the return value.
|
||||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||||
|
@ -1191,6 +1220,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
|
||||||
.Case("strlen", &CStringChecker::evalstrLength)
|
.Case("strlen", &CStringChecker::evalstrLength)
|
||||||
.Case("strnlen", &CStringChecker::evalstrnLength)
|
.Case("strnlen", &CStringChecker::evalstrnLength)
|
||||||
.Case("strcmp", &CStringChecker::evalStrcmp)
|
.Case("strcmp", &CStringChecker::evalStrcmp)
|
||||||
|
.Case("strncmp", &CStringChecker::evalStrncmp)
|
||||||
.Case("bcopy", &CStringChecker::evalBcopy)
|
.Case("bcopy", &CStringChecker::evalBcopy)
|
||||||
.Default(NULL);
|
.Default(NULL);
|
||||||
|
|
||||||
|
|
|
@ -682,3 +682,109 @@ void strcmp_diff_length_3() {
|
||||||
(void)*(char*)0; // no-warning
|
(void)*(char*)0; // no-warning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===
|
||||||
|
// strncmp()
|
||||||
|
//===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
#define strncmp BUILTIN(strncmp)
|
||||||
|
int strncmp(const char *restrict s1, const char *restrict s2, size_t n);
|
||||||
|
|
||||||
|
void strncmp_constant0() {
|
||||||
|
if (strncmp("123", "123", 3) != 0)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_constant_and_var_0() {
|
||||||
|
char *x = "123";
|
||||||
|
if (strncmp(x, "123", 3) != 0)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_constant_and_var_1() {
|
||||||
|
char *x = "123";
|
||||||
|
if (strncmp("123", x, 3) != 0)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_0() {
|
||||||
|
char *x = "123";
|
||||||
|
char *y = "123";
|
||||||
|
if (strncmp(x, y, 3) != 0)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_1() {
|
||||||
|
char *x = "234";
|
||||||
|
char *y = "123";
|
||||||
|
if (strncmp(x, y, 3) != 1)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_2() {
|
||||||
|
char *x = "123";
|
||||||
|
char *y = "234";
|
||||||
|
if (strncmp(x, y, 3) != -1)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_null_0() {
|
||||||
|
char *x = NULL;
|
||||||
|
char *y = "123";
|
||||||
|
strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_null_1() {
|
||||||
|
char *x = "123";
|
||||||
|
char *y = NULL;
|
||||||
|
strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_diff_length_0() {
|
||||||
|
char *x = "12345";
|
||||||
|
char *y = "234";
|
||||||
|
if (strncmp(x, y, 5) != -1)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_diff_length_1() {
|
||||||
|
char *x = "123";
|
||||||
|
char *y = "23456";
|
||||||
|
if (strncmp(x, y, 5) != -1)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_diff_length_2() {
|
||||||
|
char *x = "12345";
|
||||||
|
char *y = "123";
|
||||||
|
if (strncmp(x, y, 5) != 1)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_diff_length_3() {
|
||||||
|
char *x = "123";
|
||||||
|
char *y = "12345";
|
||||||
|
if (strncmp(x, y, 5) != -1)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_diff_length_4() {
|
||||||
|
char *x = "123";
|
||||||
|
char *y = "12345";
|
||||||
|
if (strncmp(x, y, 3) != 0)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_diff_length_5() {
|
||||||
|
char *x = "012";
|
||||||
|
char *y = "12345";
|
||||||
|
if (strncmp(x, y, 3) != -1)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncmp_diff_length_6() {
|
||||||
|
char *x = "234";
|
||||||
|
char *y = "12345";
|
||||||
|
if (strncmp(x, y, 3) != 1)
|
||||||
|
(void)*(char*)0; // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue