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 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
|
||||
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 {
|
||||
//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();
|
||||
|
||||
// Check that the first string is non-null
|
||||
|
@ -1142,8 +1154,25 @@ void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
|
|||
return;
|
||||
llvm::StringRef s2StrRef = s2StrLiteral->getString();
|
||||
|
||||
int result;
|
||||
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.
|
||||
int result = s1StrRef.compare(s2StrRef);
|
||||
result = s1StrRef.compare(s2StrRef);
|
||||
}
|
||||
|
||||
// Build the SVal of the comparison to bind the return value.
|
||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||
|
@ -1191,6 +1220,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
|
|||
.Case("strlen", &CStringChecker::evalstrLength)
|
||||
.Case("strnlen", &CStringChecker::evalstrnLength)
|
||||
.Case("strcmp", &CStringChecker::evalStrcmp)
|
||||
.Case("strncmp", &CStringChecker::evalStrncmp)
|
||||
.Case("bcopy", &CStringChecker::evalBcopy)
|
||||
.Default(NULL);
|
||||
|
||||
|
|
|
@ -682,3 +682,109 @@ void strcmp_diff_length_3() {
|
|||
(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